feat: WCAG-AAA-Kontraste, Cavendish-Skin, Deploy-Pipeline
Barrierefreiheit (cavendish.css / header.css): - Header auf dunkles Teal (#003535) umgestellt, Titel weiß - Tab-Buttons an dunklen Header angepasst (Kontrast 12:1 AAA) - Status-Boxen (.successbox/.errorbox/.warningbox) von <2:1 auf 7-8:1 angehoben - Grau-Texte (#888, #808080, #7d7d7d) auf #595959 (7:1 AAA) vereinheitlicht - Aktive Links, Footer, Nav-Labels auf WCAG-AAA-Kontrast gebracht - header.css in skin.json registriert (war nie geladen) - Cavendish-Skin vollständig versioniert Deploy-Infrastruktur: - .forgejo/workflows/deploy.yml: Auto-Deploy via Forgejo Actions bei Push auf main - scripts/deploy.ps1: manuelles Windows-Deploy (WSL rsync / scp-Fallback) - mediawiki/LocalSettings.production.example.php: Produktions-Konfigurationsvorlage - .deploy.example.env: Verbindungsdaten-Template - package.json: deploy / deploy:all / deploy:initial Skripte ergänzt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Deployment-Konfiguration für GPLX
|
||||||
|
# Kopiere diese Datei als .deploy.env und fülle deine Werte ein.
|
||||||
|
# .deploy.env wird NICHT ins Git-Repository übernommen.
|
||||||
|
|
||||||
|
# SSH-Verbindung
|
||||||
|
DEPLOY_HOST=deine-subdomain.bitpalast.de
|
||||||
|
DEPLOY_USER=dein-ssh-user
|
||||||
|
|
||||||
|
# Absoluter Pfad zu mediawiki/ auf dem Server
|
||||||
|
DEPLOY_MW_PATH=/var/www/html/gplx/mediawiki
|
||||||
|
|
||||||
|
# Absoluter Pfad zum Projektverzeichnis (eine Ebene über mediawiki/)
|
||||||
|
DEPLOY_PROJECT_PATH=/var/www/html/gplx
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
name: Deploy to Bitpalast
|
||||||
|
|
||||||
|
# Triggert nur wenn relevante Dateien geändert werden
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "mediawiki/skins/Cavendish/**"
|
||||||
|
- "scripts/templates/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: SSH-Key einrichten
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
|
||||||
|
chmod 600 ~/.ssh/id_rsa
|
||||||
|
ssh-keyscan -H "${{ secrets.DEPLOY_HOST }}" >> ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Cavendish-Skin deployen
|
||||||
|
run: |
|
||||||
|
rsync -az --delete \
|
||||||
|
mediawiki/skins/Cavendish/ \
|
||||||
|
"${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:${{ secrets.DEPLOY_MW_PATH }}/skins/Cavendish/"
|
||||||
|
|
||||||
|
- name: Wiki-Templates deployen
|
||||||
|
if: ${{ secrets.DEPLOY_PROJECT_PATH != '' }}
|
||||||
|
run: |
|
||||||
|
rsync -az \
|
||||||
|
scripts/templates/ \
|
||||||
|
"${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}:${{ secrets.DEPLOY_PROJECT_PATH }}/scripts/templates/"
|
||||||
|
|
@ -5,3 +5,4 @@ mediawiki/images/
|
||||||
mediawiki/vendor/
|
mediawiki/vendor/
|
||||||
mediawiki/LocalSettings.php
|
mediawiki/LocalSettings.php
|
||||||
.lighthouseci/
|
.lighthouseci/
|
||||||
|
.deploy.env
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project overview
|
||||||
|
|
||||||
|
GPLX is a local-first MediaWiki 1.43 installation on Windows, purpose-built for an accessibility-focused content workflow. The Node/npm layer wraps PowerShell scripts for setup and tooling; the actual MediaWiki application lives in `./mediawiki/`.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
| Task | Command |
|
||||||
|
|---|---|
|
||||||
|
| Clone MediaWiki core | `npm run mw:init` |
|
||||||
|
| Install PHP (Composer) deps | `npm run mw:deps` |
|
||||||
|
| First-time setup (both above) | `npm run mw:setup` |
|
||||||
|
| Start dev server (PHP built-in, port 8080) | `npm run dev` |
|
||||||
|
| Run Pa11y accessibility checks | `npm run a11y:pa11y` |
|
||||||
|
| Run Lighthouse accessibility checks | `npm run a11y:lighthouse` |
|
||||||
|
| Run all accessibility checks | `npm run a11y:all` |
|
||||||
|
|
||||||
|
**Prerequisites:** Node.js 20+, PHP 8.1+ (XAMPP or WampServer, or PHP in PATH).
|
||||||
|
|
||||||
|
After first setup, open `http://127.0.0.1:8080/mw-config/index.php` to finish the MediaWiki installer.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
gplx/
|
||||||
|
├── mediawiki/ # MediaWiki 1.43 core (cloned from Gerrit, branch REL1_43)
|
||||||
|
│ ├── LocalSettings.php # All site config and custom hooks live here
|
||||||
|
│ ├── extensions/ # 35 bundled extensions + SemanticMediaWiki 6.0.1 via Composer
|
||||||
|
│ └── skins/ # Cavendish (default), Vector, MonoBook, Timeless, MinervaNeue
|
||||||
|
├── scripts/ # PowerShell scripts (dev.ps1, mw-init.ps1, mw-deps.ps1)
|
||||||
|
│ └── templates/ # Wiki page source files (.wiki) — pushed via maintenance/run.php edit
|
||||||
|
├── tests/accessibility/ # Pa11y (pa11y.config.json) + Lighthouse (lighthouserc.json) configs
|
||||||
|
├── docs/ # Project docs (ACCESSIBILITY_WORKFLOW.md, INSTALLATION_WINDOWS.md)
|
||||||
|
└── package.json # npm entry point — all commands delegate to scripts/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key architectural decisions
|
||||||
|
|
||||||
|
**LocalSettings.php is the customization layer.** All MediaWiki configuration, hook registrations, and inline CSS lives in `mediawiki/LocalSettings.php`. There is no separate plugin or theme source tree — customizations are PHP hooks injected at startup.
|
||||||
|
|
||||||
|
**Approval workflow via ApprovedRevs.** Pages require explicit admin/reviewer approval before public visibility. A `BeforePageDisplay` hook enforces this: unapproved pages are hidden from non-creators and from the public; creators see a pending-review notice. Roles: `sysop`, `bureaucrat`, `reviewer` (the last is assignable by bureaucrats).
|
||||||
|
|
||||||
|
**Anonymous editing is disabled.** `$wgGroupPermissions["*"]["edit"] = false` — only registered users can edit.
|
||||||
|
|
||||||
|
**Default skin is Cavendish.** Loaded with `wfLoadSkin('Cavendish')`.
|
||||||
|
|
||||||
|
**PHP built-in server for local dev.** `dev.ps1` uses `php -S 127.0.0.1:8080 -t ./mediawiki`. It probes XAMPP/WampServer paths if `php` is not in PATH.
|
||||||
|
|
||||||
|
**composer.phar lives at the project root**, not inside `mediawiki/`. The `mw-deps.ps1` script downloads it on first run if absent.
|
||||||
|
|
||||||
|
**Semantic MediaWiki (SMW) 6.0.1 is installed.** Enabled via `enableSemantics('127.0.0.1:8080')` in `LocalSettings.php`. SMW adds 39 database tables (`smw_*`) and enables structured property annotations and `{{#ask:}}` queries across all wiki pages.
|
||||||
|
|
||||||
|
**Template:RegDocument annotates SMW properties.** Every page using `{{RegDocument}}` writes nine structured properties (Scope, Status, Area of validity, etc.) via `{{#set:}}`. These power the automatic queries on `Document_Index` and the category pages.
|
||||||
|
|
||||||
|
**Wiki page sources live in `scripts/templates/`.** All template and infrastructure page content is maintained as `.wiki` files and pushed via `php mediawiki/maintenance/run.php edit`. To update a wiki page, edit the `.wiki` file and re-run the push command:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Get-Content scripts/templates/<file>.wiki -Raw | D:\xampp\php\php.exe mediawiki/maintenance/run.php edit --user "Gxplex admin" --summary "..." "<Page title>"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Navigation is two-layered.** The sidebar (MediaWiki:Sidebar) links to `Document_Index` and `Special:Ask`. Category pages (e.g. `Category:Medical Devices`) embed `{{#ask:}}` queries showing all pages in that category with their metadata.
|
||||||
|
|
||||||
|
## SMW maintenance commands
|
||||||
|
|
||||||
|
| Task | Command |
|
||||||
|
|---|---|
|
||||||
|
| Initial SMW DB setup | `php mediawiki/extensions/SemanticMediaWiki/maintenance/setupStore.php --nochecks` |
|
||||||
|
| Rebuild SMW data index | `php mediawiki/extensions/SemanticMediaWiki/maintenance/rebuildData.php` |
|
||||||
|
| Rebuild property statistics | `php mediawiki/extensions/SemanticMediaWiki/maintenance/rebuildPropertyStatistics.php` |
|
||||||
|
|
||||||
|
Run `rebuildData.php` after bulk-importing pages via the maintenance script, or after updating a template that contains `{{#set:}}`.
|
||||||
|
|
||||||
|
## Accessibility baseline
|
||||||
|
|
||||||
|
- Required: WCAG 2.1 AA
|
||||||
|
- Stretch target: WCAG 2.1 AAA where practical
|
||||||
|
- Checks must pass after any template, style, or interaction change: `npm run a11y:all`
|
||||||
|
- Pa11y targets `http://127.0.0.1:8080/` and `/index.php/Main_Page` (WCAG2AA profile)
|
||||||
|
- Lighthouse asserts minimum accessibility score of 0.9 (warns, does not fail hard)
|
||||||
|
|
@ -35,7 +35,59 @@ Open http://127.0.0.1:8080 and complete the MediaWiki web installer.
|
||||||
|
|
||||||
After installer completion, place generated LocalSettings.php in mediawiki/.
|
After installer completion, place generated LocalSettings.php in mediawiki/.
|
||||||
|
|
||||||
## 6. Run accessibility checks
|
## 6. Install Semantic MediaWiki
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
php .\composer.phar --working-dir=mediawiki require mediawiki/semantic-media-wiki "~6.0" --prefer-dist --optimize-autoloader
|
||||||
|
```
|
||||||
|
|
||||||
|
Add to `mediawiki/LocalSettings.php` (after `wfLoadSkin`):
|
||||||
|
|
||||||
|
```php
|
||||||
|
wfLoadExtension( 'SemanticMediaWiki' );
|
||||||
|
enableSemantics( '127.0.0.1:8080' );
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the SMW database setup:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
php mediawiki/extensions/SemanticMediaWiki/maintenance/setupStore.php --nochecks
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Push wiki infrastructure pages
|
||||||
|
|
||||||
|
Templates, the sidebar, the document index, and category pages are maintained as `.wiki` files in `scripts/templates/`. Push them once after a fresh install:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$php = "D:\xampp\php\php.exe"
|
||||||
|
$mw = "mediawiki\maintenance\run.php"
|
||||||
|
$usr = "Gxplex admin" # replace with your admin username
|
||||||
|
|
||||||
|
$pages = @{
|
||||||
|
"Template:RegDocument" = "scripts\templates\RegDocument.wiki"
|
||||||
|
"Template:Reference" = "scripts\templates\Reference.wiki"
|
||||||
|
"MediaWiki:Sidebar" = "scripts\templates\Sidebar.wiki"
|
||||||
|
"Document Index" = "scripts\templates\DocumentIndex.wiki"
|
||||||
|
"Category:Medical Devices" = "scripts\templates\Cat_MedicalDevices.wiki"
|
||||||
|
"Category:In Vitro Diagnostics" = "scripts\templates\Cat_IVD.wiki"
|
||||||
|
"Category:Clinical" = "scripts\templates\Cat_Clinical.wiki"
|
||||||
|
"Category:Post-Market Surveillance" = "scripts\templates\Cat_PostMarket.wiki"
|
||||||
|
"Category:Labelling" = "scripts\templates\Cat_Labelling.wiki"
|
||||||
|
"Main_Page" = "scripts\templates\MainPage.wiki"
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($title in $pages.Keys) {
|
||||||
|
Get-Content $pages[$title] -Raw | & $php $mw edit --user $usr --summary "Initial setup" $title
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then rebuild the SMW data index:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
php mediawiki/extensions/SemanticMediaWiki/maintenance/rebuildData.php
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. Run accessibility checks
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run a11y:all
|
npm run a11y:all
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
# LocalSettings.php – Produktionskonfiguration
|
||||||
|
# Lege diese Datei als LocalSettings.php auf dem Server ab.
|
||||||
|
# NICHT ins Git-Repository einchecken (.gitignore beachten).
|
||||||
|
|
||||||
|
if ( !defined( 'MEDIAWIKI' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$wgSitename = "GxPlex";
|
||||||
|
$wgScriptPath = "";
|
||||||
|
|
||||||
|
# Subdomain deiner Bitpalast-Instanz (https empfohlen)
|
||||||
|
$wgServer = "https://DEINE-SUBDOMAIN.bitpalast.de";
|
||||||
|
|
||||||
|
$wgResourceBasePath = $wgScriptPath;
|
||||||
|
|
||||||
|
$wgLogos = [
|
||||||
|
'1x' => "$wgResourceBasePath/resources/assets/regulatory_wiki_icon_medical.svg",
|
||||||
|
'icon' => "$wgResourceBasePath/resources/assets/regulatory_wiki_icon_medical.svg",
|
||||||
|
];
|
||||||
|
|
||||||
|
# E-Mail (Zugangsdaten deines Mailservers eintragen)
|
||||||
|
$wgEnableEmail = true;
|
||||||
|
$wgEnableUserEmail = true;
|
||||||
|
$wgEmergencyContact = "admin@deine-domain.de";
|
||||||
|
$wgPasswordSender = "wiki@deine-domain.de";
|
||||||
|
$wgEnotifUserTalk = false;
|
||||||
|
$wgEnotifWatchlist = false;
|
||||||
|
$wgEmailAuthentication = true;
|
||||||
|
|
||||||
|
# Datenbankverbindung (Zugangsdaten von Bitpalast-Kundencenter)
|
||||||
|
$wgDBtype = "mysql";
|
||||||
|
$wgDBserver = "localhost";
|
||||||
|
$wgDBname = "DATENBANKNAME";
|
||||||
|
$wgDBuser = "DATENBANKBENUTZER";
|
||||||
|
$wgDBpassword = "DATENBANKPASSWORT";
|
||||||
|
$wgDBprefix = "";
|
||||||
|
$wgDBssl = false;
|
||||||
|
|
||||||
|
# Cache
|
||||||
|
$wgMainCacheType = CACHE_NONE;
|
||||||
|
$wgMemCachedServers = [];
|
||||||
|
|
||||||
|
# Uploads
|
||||||
|
$wgEnableUploads = true;
|
||||||
|
|
||||||
|
$wgUseInstantCommons = false;
|
||||||
|
$wgPingback = false;
|
||||||
|
$wgLanguageCode = "en";
|
||||||
|
$wgLocaltimezone = "Europe/Berlin";
|
||||||
|
|
||||||
|
# Neuen Secret Key generieren: php maintenance/run.php generateSecretKey
|
||||||
|
$wgSecretKey = "NEUEN_KEY_GENERIEREN";
|
||||||
|
$wgAuthenticationTokenVersion = "1";
|
||||||
|
$wgUpgradeKey = "NEUEN_UPGRADE_KEY_GENERIEREN";
|
||||||
|
|
||||||
|
# Rechte
|
||||||
|
$wgRightsPage = "";
|
||||||
|
$wgRightsUrl = "https://creativecommons.org/licenses/by/4.0/";
|
||||||
|
$wgRightsText = "Creative Commons Attribution";
|
||||||
|
$wgRightsIcon = "$wgResourceBasePath/resources/assets/licenses/cc-by.png";
|
||||||
|
|
||||||
|
$wgDiff3 = "";
|
||||||
|
|
||||||
|
# Skin
|
||||||
|
$wgDefaultSkin = "Cavendish";
|
||||||
|
wfLoadSkin( 'Cavendish' );
|
||||||
|
|
||||||
|
# Fehlerdetails in Produktion deaktivieren
|
||||||
|
$wgShowExceptionDetails = false;
|
||||||
|
|
||||||
|
# === CUSTOM CONFIGURATION ===
|
||||||
|
# Ab hier: identisch mit lokaler LocalSettings.php (Hooks, Permissions, SMW etc.)
|
||||||
|
# Den Abschnitt ab "// === Approved Revisions Configuration ===" aus der
|
||||||
|
# lokalen LocalSettings.php hierher kopieren.
|
||||||
|
#
|
||||||
|
# Wichtig: enableSemantics() muss die Produktions-URL verwenden:
|
||||||
|
# enableSemantics( 'DEINE-SUBDOMAIN.bitpalast.de' );
|
||||||
|
|
@ -85,7 +85,8 @@
|
||||||
"wikimedia/wait-condition-loop": "2.0.2",
|
"wikimedia/wait-condition-loop": "2.0.2",
|
||||||
"wikimedia/wrappedstring": "4.0.1",
|
"wikimedia/wrappedstring": "4.0.1",
|
||||||
"wikimedia/xmp-reader": "0.10.2",
|
"wikimedia/xmp-reader": "0.10.2",
|
||||||
"zordius/lightncandy": "1.2.6"
|
"zordius/lightncandy": "1.2.6",
|
||||||
|
"mediawiki/semantic-media-wiki": "~6.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"composer/spdx-licenses": "1.5.8",
|
"composer/spdx-licenses": "1.5.8",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
!README
|
!README
|
||||||
!.gitignore
|
!.gitignore
|
||||||
!/.vsls.json
|
!/.vsls.json
|
||||||
|
|
||||||
|
# Composer-managed extensions (installed via mediawiki/composer.json)
|
||||||
|
SemanticMediaWiki/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<svg width="135" height="145" viewBox="0 0 145 145" role="img" xmlns="http://www.w3.org/2000/svg" style="">
|
||||||
|
<title style="fill:rgb(0, 0, 0);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto">Regulatory Wiki Icon – Medical</title>
|
||||||
|
<desc style="fill:rgb(0, 0, 0);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto">Square icon with a structured regulatory node network on a clinical teal-green background.</desc>
|
||||||
|
|
||||||
|
<rect width="135" height="135" rx="22" fill="#006B6B" style="fill:rgb(0, 107, 107);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
|
||||||
|
<line x1="42" y1="42" x2="67" y2="67" stroke="#A8D8D8" stroke-width="1.5" stroke-dasharray="3 2.5" style="fill:rgb(0, 0, 0);stroke:rgb(168, 216, 216);color:rgb(255, 255, 255);stroke-width:1.5px;stroke-dasharray:3px, 2.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<line x1="93" y1="42" x2="68" y2="67" stroke="#A8D8D8" stroke-width="1.5" stroke-dasharray="3 2.5" style="fill:rgb(0, 0, 0);stroke:rgb(168, 216, 216);color:rgb(255, 255, 255);stroke-width:1.5px;stroke-dasharray:3px, 2.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<line x1="42" y1="93" x2="67" y2="68" stroke="#E8F4F4" stroke-width="1.5" stroke-dasharray="3 2.5" style="fill:rgb(0, 0, 0);stroke:rgb(232, 244, 244);color:rgb(255, 255, 255);stroke-width:1.5px;stroke-dasharray:3px, 2.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<line x1="93" y1="93" x2="68" y2="68" stroke="#E8F4F4" stroke-width="1.5" stroke-dasharray="3 2.5" style="fill:rgb(0, 0, 0);stroke:rgb(232, 244, 244);color:rgb(255, 255, 255);stroke-width:1.5px;stroke-dasharray:3px, 2.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<line x1="42" y1="42" x2="93" y2="42" stroke="#A8D8D8" stroke-width="1" stroke-dasharray="3 3" opacity="0.4" style="fill:rgb(0, 0, 0);stroke:rgb(168, 216, 216);color:rgb(255, 255, 255);stroke-width:1px;stroke-dasharray:3px, 3px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.4;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<line x1="42" y1="93" x2="93" y2="93" stroke="#E8F4F4" stroke-width="1" stroke-dasharray="3 3" opacity="0.4" style="fill:rgb(0, 0, 0);stroke:rgb(232, 244, 244);color:rgb(255, 255, 255);stroke-width:1px;stroke-dasharray:3px, 3px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.4;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
|
||||||
|
<rect x="28" y="28" width="28" height="28" rx="6" fill="#004F4F" style="fill:rgb(0, 79, 79);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="79" y="28" width="28" height="28" rx="6" fill="#004F4F" style="fill:rgb(0, 79, 79);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="28" y="79" width="28" height="28" rx="6" fill="#004F4F" style="fill:rgb(0, 79, 79);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="79" y="79" width="28" height="28" rx="6" fill="#004F4F" style="fill:rgb(0, 79, 79);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
|
||||||
|
<rect x="52" y="52" width="31" height="31" rx="7" fill="#FFFFFF" opacity="0.95" style="fill:rgb(255, 255, 255);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.95;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
|
||||||
|
<rect x="63" y="57" width="9" height="19" rx="2" fill="#006B6B" style="fill:rgb(0, 107, 107);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="58" y="62" width="19" height="9" rx="2" fill="#006B6B" style="fill:rgb(0, 107, 107);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
|
||||||
|
<circle cx="42" cy="42" r="3.5" fill="#C8E8E8" style="fill:rgb(200, 232, 232);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<circle cx="93" cy="42" r="3.5" fill="#C8E8E8" style="fill:rgb(200, 232, 232);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<circle cx="42" cy="93" r="3.5" fill="#E8F4F4" style="fill:rgb(232, 244, 244);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<circle cx="93" cy="93" r="3.5" fill="#E8F4F4" style="fill:rgb(232, 244, 244);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
|
||||||
|
<rect x="37" y="37" width="7" height="1.5" rx="1" fill="#A8D8D8" opacity="0.7" style="fill:rgb(168, 216, 216);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.7;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="37" y="41" width="5" height="1.5" rx="1" fill="#A8D8D8" opacity="0.4" style="fill:rgb(168, 216, 216);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.4;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="88" y="37" width="7" height="1.5" rx="1" fill="#A8D8D8" opacity="0.7" style="fill:rgb(168, 216, 216);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.7;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="88" y="41" width="5" height="1.5" rx="1" fill="#A8D8D8" opacity="0.4" style="fill:rgb(168, 216, 216);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.4;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="37" y="88" width="7" height="1.5" rx="1" fill="#E8F4F4" opacity="0.7" style="fill:rgb(232, 244, 244);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.7;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="37" y="92" width="5" height="1.5" rx="1" fill="#E8F4F4" opacity="0.4" style="fill:rgb(232, 244, 244);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.4;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="88" y="88" width="7" height="1.5" rx="1" fill="#E8F4F4" opacity="0.7" style="fill:rgb(232, 244, 244);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.7;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
<rect x="88" y="92" width="5" height="1.5" rx="1" fill="#E8F4F4" opacity="0.4" style="fill:rgb(232, 244, 244);stroke:none;color:rgb(255, 255, 255);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.4;font-family:"Anthropic Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -2,3 +2,4 @@
|
||||||
!/.gitignore
|
!/.gitignore
|
||||||
!/.vsls.json
|
!/.vsls.json
|
||||||
!/README
|
!/README
|
||||||
|
!/Cavendish
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
#################
|
||||||
|
## Eclipse
|
||||||
|
#################
|
||||||
|
|
||||||
|
*.pydevproject
|
||||||
|
.project
|
||||||
|
.metadata
|
||||||
|
bin/
|
||||||
|
tmp/
|
||||||
|
*.tmp
|
||||||
|
*.bak
|
||||||
|
*.swp
|
||||||
|
*~.nib
|
||||||
|
local.properties
|
||||||
|
.classpath
|
||||||
|
.settings/
|
||||||
|
.loadpath
|
||||||
|
|
||||||
|
# External tool builders
|
||||||
|
.externalToolBuilders/
|
||||||
|
|
||||||
|
# Locally stored "Eclipse launch configurations"
|
||||||
|
*.launch
|
||||||
|
|
||||||
|
# CDT-specific
|
||||||
|
.cproject
|
||||||
|
|
||||||
|
# PDT-specific
|
||||||
|
.buildpath
|
||||||
|
|
||||||
|
|
||||||
|
#################
|
||||||
|
## Visual Studio
|
||||||
|
#################
|
||||||
|
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Rr]elease/
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.vspscc
|
||||||
|
.builds
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
## TODO: If you have NuGet Package Restore enabled, uncomment this
|
||||||
|
#packages/
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish
|
||||||
|
|
||||||
|
# Others
|
||||||
|
[Bb]in
|
||||||
|
[Oo]bj
|
||||||
|
sql
|
||||||
|
TestResults
|
||||||
|
*.Cache
|
||||||
|
ClientBin
|
||||||
|
stylecop.*
|
||||||
|
~$*
|
||||||
|
*.dbmdl
|
||||||
|
Generated_Code #added for RIA/Silverlight projects
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file to a newer
|
||||||
|
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
############
|
||||||
|
## Windows
|
||||||
|
############
|
||||||
|
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
/node_modules
|
||||||
|
/vendor
|
||||||
|
/composer.lock
|
||||||
|
/.eslintcache
|
||||||
|
|
||||||
|
|
||||||
|
#############
|
||||||
|
## Python
|
||||||
|
#############
|
||||||
|
|
||||||
|
*.py[co]
|
||||||
|
|
||||||
|
# Packages
|
||||||
|
*.egg
|
||||||
|
*.egg-info
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
eggs
|
||||||
|
parts
|
||||||
|
bin
|
||||||
|
var
|
||||||
|
sdist
|
||||||
|
develop-eggs
|
||||||
|
.installed.cfg
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
.coverage
|
||||||
|
.tox
|
||||||
|
|
||||||
|
#Translations
|
||||||
|
*.mo
|
||||||
|
|
||||||
|
#Mr Developer
|
||||||
|
.mr.developer.cfg
|
||||||
|
|
||||||
|
# Mac crap
|
||||||
|
.DS_Store
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
[gerrit]
|
||||||
|
host=gerrit.wikimedia.org
|
||||||
|
port=29418
|
||||||
|
project=mediawiki/skins/Cavendish.git
|
||||||
|
track=1
|
||||||
|
defaultrebase=0
|
||||||
|
defaultbranch=master
|
||||||
|
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
@ -0,0 +1,542 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use MediaWiki\Html\Html;
|
||||||
|
use MediaWiki\Linker\Linker;
|
||||||
|
use MediaWiki\MediaWikiServices;
|
||||||
|
use MediaWiki\ResourceLoader\SkinModule;
|
||||||
|
|
||||||
|
class CavendishTemplate extends BaseTemplate {
|
||||||
|
public $skin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the toolbox, complete with all three old hooks
|
||||||
|
*
|
||||||
|
* @return string html
|
||||||
|
*/
|
||||||
|
protected function getToolboxBox() {
|
||||||
|
$html = '';
|
||||||
|
$template = $this;
|
||||||
|
|
||||||
|
return $this->getBox( 'tb',
|
||||||
|
$this->data['sidebar']['TOOLBOX'],
|
||||||
|
'toolbox'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the languages box
|
||||||
|
*
|
||||||
|
* @return string html
|
||||||
|
*/
|
||||||
|
protected function getLanguageBox() {
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
if ( $this->data['language_urls'] !== false ) {
|
||||||
|
$html .= $this->getBox( 'lang', $this->data['language_urls'], 'otherlanguages' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for getPortlet
|
||||||
|
*
|
||||||
|
* Merge all provided css classes into a single array
|
||||||
|
* Account for possible different input methods matching what Html::element stuff takes
|
||||||
|
*
|
||||||
|
* @param string|array $class base portlet/body class
|
||||||
|
* @param string|array $extraClasses any extra classes to also include
|
||||||
|
*
|
||||||
|
* @return array all classes to apply
|
||||||
|
*/
|
||||||
|
protected function mergeClasses( $class, $extraClasses ) {
|
||||||
|
if ( !is_array( $class ) ) {
|
||||||
|
$class = [ $class ];
|
||||||
|
}
|
||||||
|
if ( !is_array( $extraClasses ) ) {
|
||||||
|
$extraClasses = [ $extraClasses ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge( $class, $extraClasses );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a block of navigation links with a header
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param array|string $content array of links for use with makeListItem, or a block of text
|
||||||
|
* @param null|string|array $msg
|
||||||
|
* @param array $setOptions random crap to rename/do/whatever
|
||||||
|
*
|
||||||
|
* @return string html
|
||||||
|
*/
|
||||||
|
protected function getPortlet( $name, $content, $msg = null, $setOptions = [] ) {
|
||||||
|
// random stuff to override with any provided options
|
||||||
|
$options = array_merge( [
|
||||||
|
// handle role=search a little differently
|
||||||
|
'role' => 'navigation',
|
||||||
|
'search-input-id' => 'searchInput',
|
||||||
|
// extra classes/ids
|
||||||
|
'id' => 'p-' . $name,
|
||||||
|
'class' => 'mw-portlet',
|
||||||
|
'extra-classes' => '',
|
||||||
|
'body-id' => null,
|
||||||
|
'body-class' => 'mw-portlet-body',
|
||||||
|
'body-extra-classes' => '',
|
||||||
|
// wrapper for individual list items
|
||||||
|
'text-wrapper' => [ 'tag' => 'span' ],
|
||||||
|
// old toolbox hook support (use: [ 'SkinTemplateToolboxEnd' => [ &$skin, true ] ])
|
||||||
|
'hooks' => '',
|
||||||
|
// option to stick arbitrary stuff at the beginning of the ul
|
||||||
|
'list-prepend' => ''
|
||||||
|
], $setOptions );
|
||||||
|
|
||||||
|
// Handle the different $msg possibilities
|
||||||
|
if ( $msg === null ) {
|
||||||
|
$msg = $name;
|
||||||
|
$msgParams = [];
|
||||||
|
} elseif ( is_array( $msg ) ) {
|
||||||
|
$msgString = array_shift( $msg );
|
||||||
|
$msgParams = $msg;
|
||||||
|
$msg = $msgString;
|
||||||
|
} else {
|
||||||
|
$msgParams = [];
|
||||||
|
}
|
||||||
|
$msgObj = $this->getMsg( $msg, $msgParams );
|
||||||
|
if ( $msgObj->exists() ) {
|
||||||
|
$msgString = $msgObj->parse();
|
||||||
|
} else {
|
||||||
|
$msgString = htmlspecialchars( $msg );
|
||||||
|
}
|
||||||
|
|
||||||
|
$labelId = Sanitizer::escapeIdForAttribute( "p-$name-label" );
|
||||||
|
|
||||||
|
if ( is_array( $content ) ) {
|
||||||
|
$contentText = Html::openElement( 'ul',
|
||||||
|
[ 'lang' => $this->get( 'userlang' ), 'dir' => $this->get( 'dir' ) ]
|
||||||
|
);
|
||||||
|
$contentText .= $options['list-prepend'];
|
||||||
|
foreach ( $content as $key => $item ) {
|
||||||
|
if ( is_array( $options['text-wrapper'] ) ) {
|
||||||
|
$contentText .= $this->makeListItem(
|
||||||
|
$key,
|
||||||
|
$item,
|
||||||
|
[ 'text-wrapper' => $options['text-wrapper'] ]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$contentText .= $this->makeListItem(
|
||||||
|
$key,
|
||||||
|
$item
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$contentText .= Html::closeElement( 'ul' );
|
||||||
|
} else {
|
||||||
|
$contentText = $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special handling for role=search
|
||||||
|
$divOptions = [
|
||||||
|
'role' => $options['role'],
|
||||||
|
'class' => $this->mergeClasses( $options['class'], $options['extra-classes'] ),
|
||||||
|
'id' => Sanitizer::escapeIdForAttribute( $options['id'] ),
|
||||||
|
'title' => Linker::titleAttrib( $options['id'] )
|
||||||
|
];
|
||||||
|
if ( $options['role'] !== 'search' ) {
|
||||||
|
$divOptions['aria-labelledby'] = $labelId;
|
||||||
|
}
|
||||||
|
$labelOptions = [
|
||||||
|
'id' => $labelId,
|
||||||
|
'lang' => $this->get( 'userlang' ),
|
||||||
|
'dir' => $this->get( 'dir' )
|
||||||
|
];
|
||||||
|
if ( $options['role'] == 'search' ) {
|
||||||
|
$msgString = Html::rawElement( 'label', [ 'for' => $options['search-input-id'] ], $msgString );
|
||||||
|
}
|
||||||
|
|
||||||
|
$bodyDivOptions = [
|
||||||
|
'class' => $this->mergeClasses( $options['body-class'], $options['body-extra-classes'] )
|
||||||
|
];
|
||||||
|
if ( is_string( $options['body-id'] ) ) {
|
||||||
|
$bodyDivOptions['id'] = $options['body-id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = Html::rawElement( 'div', $divOptions,
|
||||||
|
Html::rawElement( 'h3', $labelOptions, $msgString ) .
|
||||||
|
Html::rawElement( 'div', $bodyDivOptions,
|
||||||
|
$contentText .
|
||||||
|
$this->getSkin()->getAfterPortlet( $name )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a sidebar box using getPortlet(); prefill some common stuff
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param array|string $contents
|
||||||
|
* @param-taint $contents escapes_htmlnoent
|
||||||
|
* @param null|string|array|bool $msg
|
||||||
|
* @param array $setOptions
|
||||||
|
*
|
||||||
|
* @return string html
|
||||||
|
*/
|
||||||
|
protected function getBox( $name, $contents, $msg = null, $setOptions = [] ) {
|
||||||
|
$options = array_merge( [
|
||||||
|
'class' => 'portlet',
|
||||||
|
'body-class' => 'pBody',
|
||||||
|
'text-wrapper' => ''
|
||||||
|
], $setOptions );
|
||||||
|
|
||||||
|
// Do some special stuff for the personal menu
|
||||||
|
if ( $name == 'personal' ) {
|
||||||
|
$prependiture = '';
|
||||||
|
|
||||||
|
// Extension:UniversalLanguageSelector order - T121793
|
||||||
|
if ( array_key_exists( 'uls', $contents ) ) {
|
||||||
|
$prependiture .= $this->makeListItem( 'uls', $contents['uls'] );
|
||||||
|
unset( $contents['uls'] );
|
||||||
|
}
|
||||||
|
if ( !$this->getSkin()->getUser()->isLoggedIn() &&
|
||||||
|
MediaWikiServices::getInstance()->getGroupPermissionsLookup()
|
||||||
|
->groupHasPermission( '*', 'edit' )
|
||||||
|
) {
|
||||||
|
$prependiture .= Html::rawElement(
|
||||||
|
'li',
|
||||||
|
[ 'id' => 'pt-anonuserpage' ],
|
||||||
|
$this->getMsg( 'notloggedin' )->escaped()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$options['list-prepend'] = $prependiture;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getPortlet( $name, $contents, $msg, $options );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the search, using config options for buttons (?)
|
||||||
|
*
|
||||||
|
* @return string html
|
||||||
|
*/
|
||||||
|
protected function getSearchBox() {
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
$optionButtons = "\u{00A0} " . $this->makeSearchButton(
|
||||||
|
'fulltext',
|
||||||
|
[
|
||||||
|
'id' => 'mw-searchButton',
|
||||||
|
'class' => 'searchButton',
|
||||||
|
'value' => $this->getMsg( 'searchbutton' )->text()
|
||||||
|
]
|
||||||
|
);
|
||||||
|
$searchInputId = 'searchInput';
|
||||||
|
$searchForm = Html::rawElement( 'form', [
|
||||||
|
'action' => $this->get( 'wgScript' ),
|
||||||
|
'id' => 'searchform'
|
||||||
|
],
|
||||||
|
Html::hidden( 'title', $this->get( 'searchtitle' ) ) .
|
||||||
|
$this->makeSearchInput( [ 'id' => $searchInputId ] ) .
|
||||||
|
$this->makeSearchButton( 'go', [
|
||||||
|
'id' => 'searchGoButton',
|
||||||
|
'class' => 'searchButton',
|
||||||
|
'value' => $this->getMsg( 'searcharticle' )->text()
|
||||||
|
] ) .
|
||||||
|
$optionButtons
|
||||||
|
);
|
||||||
|
|
||||||
|
$html .= $this->getBox( 'search', $searchForm, null, [
|
||||||
|
'search-input-id' => $searchInputId,
|
||||||
|
'role' => 'search',
|
||||||
|
'body-id' => 'searchBody'
|
||||||
|
] );
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the class for the globalWrapper element
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getGlobalWrapperAttributes( Config $config, string $action ): string {
|
||||||
|
$siteWidth = $config->get( 'CavendishSiteWidth' );
|
||||||
|
$qrCodeMode = $config->get( 'CavendishQRCodeMode' );
|
||||||
|
$sidebarSearchbox = $config->get( 'CavendishSidebarSearchbox' );
|
||||||
|
|
||||||
|
$classes = [
|
||||||
|
htmlspecialchars( $action, ENT_QUOTES )
|
||||||
|
];
|
||||||
|
if ( $qrCodeMode === 'print' ) {
|
||||||
|
$classes[] = 'cavendish-qr-code-mode-print';
|
||||||
|
} elseif ( $qrCodeMode === 'all' ) {
|
||||||
|
$classes[] = 'cavendish-qr-code-mode-all';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $sidebarSearchbox ) {
|
||||||
|
$classes[] = 'cavendish-sidebar-searchbox';
|
||||||
|
}
|
||||||
|
return Html::expandAttributes( [
|
||||||
|
'id' => 'globalWrapper',
|
||||||
|
'class' => $classes,
|
||||||
|
'style' => $siteWidth !== false ? 'width: ' . $sideWidth . 'px;' : null,
|
||||||
|
] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template filter callback for Cavendish skin.
|
||||||
|
* Takes an associative array of data set from a SkinTemplate-based
|
||||||
|
* class, and a wrapper for MediaWiki's localization database, and
|
||||||
|
* outputs a formatted page.
|
||||||
|
*/
|
||||||
|
function execute() {
|
||||||
|
$this->skin = $skin = $this->data['skin'];
|
||||||
|
$action = $skin->getRequest()->getText( 'action', 'view' );
|
||||||
|
$config = $skin->getConfig();
|
||||||
|
|
||||||
|
$this->data['pageLanguage'] =
|
||||||
|
$skin->getTitle()->getPageLanguage()->getHtmlCode();
|
||||||
|
|
||||||
|
// <body> starts here
|
||||||
|
?>
|
||||||
|
<div id="internal"></div>
|
||||||
|
<div <?php echo $this->getGlobalWrapperAttributes( $config, $action ) ?>>
|
||||||
|
<div id="p-personal" class="portlet">
|
||||||
|
<h5><?php $this->msg( 'personaltools' ) ?></h5>
|
||||||
|
<div class="pBody">
|
||||||
|
<ul<?php $this->html( 'userlangattributes' ) ?>>
|
||||||
|
<?php
|
||||||
|
$personalTools = $this->getPersonalTools();
|
||||||
|
foreach ( $personalTools as $key => $item ) {
|
||||||
|
?>
|
||||||
|
<li id="<?php echo Sanitizer::escapeIdForAttribute( "pt-$key" ) ?>" class="<?php
|
||||||
|
if ( $item['active'] ?? false ) { ?>active <?php } ?>top-nav-element">
|
||||||
|
<span class="top-nav-left"> </span>
|
||||||
|
<?php
|
||||||
|
// Crappy hack for Echo
|
||||||
|
// Without this the Echo links will generate an E_NOTICE:
|
||||||
|
// Notice: Array to string conversion in ../includes/skins/BaseTemplate.php on line 410
|
||||||
|
if ( isset( $item['links'][0]['class'] ) && is_array( $item['links'][0]['class'] ) ) {
|
||||||
|
$classHTML = '';
|
||||||
|
foreach ( $item['links'][0]['class'] as $class ) {
|
||||||
|
$classHTML .= $class . ' ';
|
||||||
|
}
|
||||||
|
$item['links'][0]['class'] = $classHTML;
|
||||||
|
}
|
||||||
|
if ( $key !== 'anonuserpage' ) {
|
||||||
|
echo $this->makeLink( $key, $item['links'][0], [ 'link-class' => 'top-nav-mid' ] );
|
||||||
|
} else {
|
||||||
|
// Stupid hack for anonuserpage, which is the "Not logged in" text, which is indeed
|
||||||
|
// just a snippet of text, not a link; but we still need the class there to have the area
|
||||||
|
// display properly
|
||||||
|
echo '<p class="top-nav-mid">' . $this->makeLink( $key, $item['links'][0] ) . '</p>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<span class="top-nav-right"> </span>
|
||||||
|
</li>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="header">
|
||||||
|
<a name="top" id="contentTop"></a>
|
||||||
|
<div id="site-logo">
|
||||||
|
<?php
|
||||||
|
$logos = SkinModule::getAvailableLogos( $config );
|
||||||
|
$logoUrl = $logos['1x'] ?? null;
|
||||||
|
$logoAttributes = [
|
||||||
|
'href' => $this->data['nav_urls']['mainpage']['href'],
|
||||||
|
'title' => $this->getMsg( 'mainpage' ),
|
||||||
|
'id' => 'site-logo-link',
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
<a <?php echo Html::expandAttributes( $logoAttributes ); ?>>
|
||||||
|
<?php if ( $logoUrl ): ?>
|
||||||
|
<img src="<?php echo htmlspecialchars( $logoUrl ) ?>" width="48" height="48" alt="">
|
||||||
|
<?php endif; ?>
|
||||||
|
<span id="site-name"><?php $this->text( 'pagetitle' ) ?></span>
|
||||||
|
</a></div>
|
||||||
|
<div id="p-cactions" class="portlet" role="navigation">
|
||||||
|
<ul>
|
||||||
|
<?php
|
||||||
|
foreach ( $this->data['content_actions'] as $key => $tab ) {
|
||||||
|
echo $this->makeListItem( $key, $tab );
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
// TODO Searchbox Handling
|
||||||
|
echo $this->getSearchBox();
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<div id="mBody">
|
||||||
|
<div id="side">
|
||||||
|
<div id="nav">
|
||||||
|
<?php echo $this->renderPortals( $this->data['sidebar'] ); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- end of #mBody div -->
|
||||||
|
<div id="column-content">
|
||||||
|
<div id="content" class="mw-body">
|
||||||
|
<a id="top"></a>
|
||||||
|
<?php if ( $this->data['sitenotice'] ) { ?><div id="siteNotice"><?php $this->html( 'sitenotice' ) ?></div><?php } ?>
|
||||||
|
<?php echo $this->getIndicators() ?>
|
||||||
|
<h1 id="firstHeading" class="firstHeading" lang="<?php $this->text( 'pageLanguage' ); ?>"><?php $this->html( 'title' ) ?></h1>
|
||||||
|
<div id="bodyContent" class="mw-body-content">
|
||||||
|
<h3 id="siteSub"><?php $this->msg( 'tagline' ) ?></h3>
|
||||||
|
<div id="contentSub"<?php $this->html( 'userlangattributes' ) ?>><?php $this->html( 'subtitle' ) ?></div>
|
||||||
|
<?php if ( $this->data['undelete'] ) { ?><div id="contentSub2"><?php $this->html( 'undelete' ) ?></div><?php } ?>
|
||||||
|
<?php if ( $this->data['newtalk'] ) { ?><div class="usermessage"><?php $this->html( 'newtalk' ) ?></div><?php } ?>
|
||||||
|
<div id="jump-to-nav" class="mw-jump"><?php $this->msg( 'jumpto' ) ?> <a href="#column-one"><?php $this->msg( 'jumptonavigation' ) ?></a>, <a href="#searchInput"><?php $this->msg( 'jumptosearch' ) ?></a></div>
|
||||||
|
<!-- start content -->
|
||||||
|
<?php
|
||||||
|
$this->html( 'bodytext' );
|
||||||
|
if ( $this->data['catlinks'] ) {
|
||||||
|
$this->html( 'catlinks' );
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!-- end content -->
|
||||||
|
<?php
|
||||||
|
if ( $this->data['dataAfterContent'] ) {
|
||||||
|
$this->html( 'dataAfterContent' );
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div><!-- end of #content div -->
|
||||||
|
</div>
|
||||||
|
</div><!-- end of #globalWrapper div -->
|
||||||
|
<div class="visualClear"></div>
|
||||||
|
<div id="footer" role="contentinfo"<?php $this->html( 'userlangattributes' ) ?>>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="f-iconsection">
|
||||||
|
<?php
|
||||||
|
$icons = $this->get( 'footericons' );
|
||||||
|
$icon = $icons['copyright'][0] ?? null;
|
||||||
|
if ( $icon ) {
|
||||||
|
?><div id="f-copyrightico"><?php
|
||||||
|
echo $skin->makeFooterIcon( $icon );
|
||||||
|
?></div><?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<?php // Generate additional footer links
|
||||||
|
$footerLinks = [
|
||||||
|
'lastmod', 'viewcount', 'credits', 'copyright',
|
||||||
|
'privacy', 'about', 'disclaimer', 'tagline',
|
||||||
|
];
|
||||||
|
|
||||||
|
$validFooterLinks = [];
|
||||||
|
foreach ( $footerLinks as $aLink ) {
|
||||||
|
if ( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {
|
||||||
|
$validFooterLinks[] = $aLink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( count( $validFooterLinks ) > 0 ) {
|
||||||
|
?> <ul id="f-list">
|
||||||
|
<?php
|
||||||
|
foreach ( $validFooterLinks as $aLink ) {
|
||||||
|
if ( isset( $this->data[$aLink] ) && $this->data[$aLink] ) {
|
||||||
|
?> <li id="f-<?php echo $aLink ?>"><?php $this->html( $aLink ) ?></li>
|
||||||
|
<?php }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td rowspan="2" class="f-iconsection">
|
||||||
|
<?php
|
||||||
|
$validFooterIcons = $this->get( 'footericons' );
|
||||||
|
unset( $validFooterIcons['copyright'] );
|
||||||
|
foreach ( $validFooterIcons as $blockName => $footerIcons ) { ?>
|
||||||
|
<div id="f-<?php echo htmlspecialchars( $blockName ); ?>ico"><?php
|
||||||
|
foreach ( $footerIcons as $icon ) {
|
||||||
|
// Need to check emptiness before rendering to prevent core from throwing
|
||||||
|
// an E_NOTICE:
|
||||||
|
// PHP Notice: Undefined index: alt in <path to MW>/includes/skins/Skin.php on line 1007
|
||||||
|
if ( !empty( $icon ) ) {
|
||||||
|
echo $this->skin->makeFooterIcon( $icon );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?></div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
// Show a Quick Response (QR) code if enabled in configuration
|
||||||
|
if ( $this->config->get( 'CavendishQRCode' ) ) {
|
||||||
|
$QRURL = htmlentities( $skin->getTitle()->getFullURL() ) . $this->config->get( 'CavendishQRUrlAdd' );
|
||||||
|
?>
|
||||||
|
<div id="qrcode">
|
||||||
|
<a href="http://goqr.me/" style="border:0 none;cursor:default;text-decoration:none;">
|
||||||
|
<img src="http://api.qrserver.com/v1/create-qr-code/?data=<?php echo $QRURL; ?>&size=160x160" height="80" width="80" alt="QR Code generator" title="" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<?php } ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<div id="skin-info">
|
||||||
|
<?php echo $skin->msg( 'cavendish-skin-info', '3.0.0' )->parse() ?>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div><!-- end of the FOOTER div -->
|
||||||
|
<!-- scripts and debugging information -->
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @todo FIXME: this is literal copypasta from MonoBookTemplate.php just
|
||||||
|
* so that we can comment out one line. That sucks.
|
||||||
|
* @param array $sidebar
|
||||||
|
*/
|
||||||
|
protected function renderPortals( $sidebar ) {
|
||||||
|
$html = '';
|
||||||
|
$languagesHTML = '';
|
||||||
|
|
||||||
|
if ( !isset( $sidebar['SEARCH'] ) ) {
|
||||||
|
$sidebar['SEARCH'] = true;
|
||||||
|
}
|
||||||
|
if ( !isset( $sidebar['TOOLBOX'] ) ) {
|
||||||
|
$sidebar['TOOLBOX'] = true;
|
||||||
|
}
|
||||||
|
if ( !isset( $sidebar['LANGUAGES'] ) ) {
|
||||||
|
$sidebar['LANGUAGES'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $sidebar as $boxName => $content ) {
|
||||||
|
if ( $content === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Numeric strings gets an integer when set as key, cast back - T73639
|
||||||
|
$boxName = (string)$boxName;
|
||||||
|
|
||||||
|
if ( $boxName == 'SEARCH' ) {
|
||||||
|
// ignore.
|
||||||
|
} elseif ( $boxName == 'TOOLBOX' ) {
|
||||||
|
$html .= $this->getToolboxBox( $content );
|
||||||
|
} elseif ( $boxName == 'LANGUAGES' ) {
|
||||||
|
$languagesHTML = $this->getLanguageBox( $content );
|
||||||
|
} else {
|
||||||
|
$html .= $this->getBox(
|
||||||
|
$boxName,
|
||||||
|
$content,
|
||||||
|
null,
|
||||||
|
[ 'extra-classes' => 'generated-sidebar' ]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output language portal last given it can be long
|
||||||
|
// on articles which support multiple languages (T254546)
|
||||||
|
return $html . $languagesHTML;
|
||||||
|
}
|
||||||
|
} // end of class
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*jshint node:true */
|
||||||
|
module.exports = function ( grunt ) {
|
||||||
|
grunt.loadNpmTasks( 'grunt-banana-checker' );
|
||||||
|
grunt.loadNpmTasks( 'grunt-jsonlint' );
|
||||||
|
|
||||||
|
grunt.initConfig( {
|
||||||
|
banana: {
|
||||||
|
all: 'i18n/'
|
||||||
|
},
|
||||||
|
jsonlint: {
|
||||||
|
all: [
|
||||||
|
'**/*.json',
|
||||||
|
'!node_modules/**'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
grunt.registerTask( 'test', [ 'jsonlint', 'banana' ] );
|
||||||
|
grunt.registerTask( 'default', 'test' );
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Cavendish
|
||||||
|
Cavendish MediaWiki skin version 2.6.0
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
This version of the skin is compatible with MW 1.35+
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
There are different options that can be set in `LocalSettings.php`.
|
||||||
|
|
||||||
|
`$wgLogos['1x-options'] = [ 'width' => 10, 'height' => 20, 'margin' => 10 ]`
|
||||||
|
* width of the logo as a number in px
|
||||||
|
* height of the logo as a number in px
|
||||||
|
* offset on top of the logo
|
||||||
|
|
||||||
|
`$wgCavendishSiteWidth`
|
||||||
|
fixed width of the content area, if not set it's dynamic (default is false, that means dynamic)
|
||||||
|
|
||||||
|
`$wgCavendishQRCode`
|
||||||
|
Whether to add QR code to all pages (true) or not (false)
|
||||||
|
|
||||||
|
`$wgCavendishQRUrlAdd`
|
||||||
|
Used to track campaign for entry through QR Code in analytics software (e.g. Google Analytics, Piwik, ...); default is "?pk_campaign=qr-code"
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"require-dev": {
|
||||||
|
"mediawiki/minus-x": "1.1.3",
|
||||||
|
"php-parallel-lint/php-console-highlighter": "1.0.0",
|
||||||
|
"php-parallel-lint/php-parallel-lint": "1.4.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": [
|
||||||
|
"parallel-lint . --exclude vendor --exclude node_modules",
|
||||||
|
"minus-x check ."
|
||||||
|
],
|
||||||
|
"fix": [
|
||||||
|
"minus-x fix ."
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"@metadata": {
|
||||||
|
"authors": ["DaSch"]
|
||||||
|
},
|
||||||
|
"cavendish-prefs-talkpage": "[[mw:Skin talk:Cavendish|{{int:talk}}]]",
|
||||||
|
"cavendish.css": "/* CSS placed here will affect users of the Cavendish skin */",
|
||||||
|
"cavendish.js": "/* Any JavaScript here will be loaded for users using the Cavendish skin */",
|
||||||
|
"skinname-cavendish": "Cavendish (Blue)",
|
||||||
|
"skinname-cavendish-green": "Cavendish (Green)",
|
||||||
|
"skinname-cavendish-brown": "Cavendish (Brown)",
|
||||||
|
"cavendish-desc": "Mozilla Cavendish skin. Modified by DaSch for MW 1.19 and WeCoWi.",
|
||||||
|
"cavendish-skin-info": "Mozilla Cavendish skin<br />[https://phabricator.wikimedia.org/maniphest/task/edit/form/43/?tags=mediawiki-skins-Cavendish Report a bug] – Skin version: $1"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/* Blue color */
|
||||||
|
|
||||||
|
#header {
|
||||||
|
background: #455372; /* Old browsers */
|
||||||
|
background: -moz-linear-gradient(top, #455372 0%, #455372 52%, #3f4c6b 67%, #2a3753 100%); /* FF3.6+ */
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#455372), color-stop(52%,#455372), color-stop(67%,#3f4c6b), color-stop(100%,#2a3753)); /* Chrome,Safari4+ */
|
||||||
|
background: -webkit-linear-gradient(top, #455372 0%,#455372 52%,#3f4c6b 67%,#2a3753 100%); /* Chrome10+,Safari5.1+ */
|
||||||
|
background: -o-linear-gradient(top, #455372 0%,#455372 52%,#3f4c6b 67%,#2a3753 100%); /* Opera 11.10+ */
|
||||||
|
background: -ms-linear-gradient(top, #455372 0%,#455372 52%,#3f4c6b 67%,#2a3753 100%); /* IE10+ */
|
||||||
|
background: linear-gradient(to bottom, #455372 0%,#455372 52%,#3f4c6b 67%,#2a3753 100%); /* W3C */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#455372', endColorstr='#2a3753',GradientType=0 ); /* IE6-9 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#header form label, #header label {
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header form #searchInput {
|
||||||
|
border: 1px solid #9097a2;
|
||||||
|
background-color: #d9dbe1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* p-cactions */
|
||||||
|
#p-cactions li {
|
||||||
|
border-bottom: 1px solid #515358;
|
||||||
|
background-color: #5F697e;
|
||||||
|
border-top-color: #5F697e;
|
||||||
|
}
|
||||||
|
|
||||||
|
#p-cactions li:hover {
|
||||||
|
border-top-color: #747f96;
|
||||||
|
background-color: #747f96;
|
||||||
|
}
|
||||||
|
|
||||||
|
#p-cactions li.selected a {
|
||||||
|
color: #455372;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NAV */
|
||||||
|
#nav {
|
||||||
|
background: #e0e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div a:hover {
|
||||||
|
background: #e0e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div a,
|
||||||
|
#nav div span.social {
|
||||||
|
background: #edf2f2;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
border-top: 1px solid #fff;
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* preftoc */
|
||||||
|
#preftoc li:hover,
|
||||||
|
#preftoc li:focus,
|
||||||
|
#preftoc li.selected {
|
||||||
|
background-color: #e0e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fieldset */
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #2f6fab;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset fieldset {
|
||||||
|
background-color: #e0e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mw-line */
|
||||||
|
.mw-line-odd {
|
||||||
|
background-color: #edf2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mw-line-even {
|
||||||
|
background-color: #e0e9e9;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
/* Brown color */
|
||||||
|
|
||||||
|
#header {
|
||||||
|
background: #e3cead; /* Old browsers */
|
||||||
|
background: -moz-linear-gradient(top, #e3cead 0%, #dac39e 35%, #ccb186 75%, #c5aa7d 100%); /* FF3.6+ */
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#e3cead), color-stop(35%,#dac39e), color-stop(75%,#ccb186), color-stop(100%,#c5aa7d)); /* Chrome,Safari4+ */
|
||||||
|
background: -webkit-linear-gradient(top, #e3cead 0%,#dac39e 35%,#ccb186 75%,#c5aa7d 100%); /* Chrome10+,Safari5.1+ */
|
||||||
|
background: -o-linear-gradient(top, #e3cead 0%,#dac39e 35%,#ccb186 75%,#c5aa7d 100%); /* Opera 11.10+ */
|
||||||
|
background: -ms-linear-gradient(top, #e3cead 0%,#dac39e 35%,#ccb186 75%,#c5aa7d 100%); /* IE10+ */
|
||||||
|
background: linear-gradient(to bottom, #e3cead 0%,#dac39e 35%,#ccb186 75%,#c5aa7d 100%); /* W3C */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e3cead', endColorstr='#c5aa7d',GradientType=0 ); /* IE6-9 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#header form label,
|
||||||
|
#header label {
|
||||||
|
color: #774f03;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header form #searchInput {
|
||||||
|
border: 1px solid #774f03;
|
||||||
|
background-color: #fbf4e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* p-cactions */
|
||||||
|
#p-cactions li {
|
||||||
|
border-bottom: 1px solid #b48a48;
|
||||||
|
background-color: #885e1b;
|
||||||
|
border-top-color: #885e1b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#p-cactions li:hover {
|
||||||
|
border-top-color: #b48a48;
|
||||||
|
background-color: #b48a48;
|
||||||
|
}
|
||||||
|
|
||||||
|
#p-cactions li.selected a {
|
||||||
|
color: #780000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NAV */
|
||||||
|
#nav {
|
||||||
|
background: #e8ddca;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div a:hover {
|
||||||
|
background: #e8ddca;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div a,
|
||||||
|
#nav div span.social {
|
||||||
|
background-color:#fbf4e8;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
border-top: 1px solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* preftoc */
|
||||||
|
#preftoc li:hover,
|
||||||
|
#preftoc li:focus,
|
||||||
|
#preftoc li.selected {
|
||||||
|
background-color: #e8ddca;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fieldset */
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #774F03;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset fieldset {
|
||||||
|
background-color: #e8ddca;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mw-line */
|
||||||
|
.mw-line-odd {
|
||||||
|
background-color: #FBF4E8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mw-line-even {
|
||||||
|
background-color: #e8ddca;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* different from blue.css */
|
||||||
|
.portlet li a:link {
|
||||||
|
color: #780000;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.portlet li a:visited {
|
||||||
|
color: #774f03;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
/* Green color */
|
||||||
|
|
||||||
|
#header {
|
||||||
|
background: #379940; /* Old browsers */
|
||||||
|
background: -moz-linear-gradient(top, #379940 0%, #36983f 56%, #32903a 68%, #216d2b 100%); /* FF3.6+ */
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#379940), color-stop(56%,#36983f), color-stop(68%,#32903a), color-stop(100%,#216d2b)); /* Chrome,Safari4+ */
|
||||||
|
background: -webkit-linear-gradient(top, #379940 0%,#36983f 56%,#32903a 68%,#216d2b 100%); /* Chrome10+,Safari5.1+ */
|
||||||
|
background: -o-linear-gradient(top, #379940 0%,#36983f 56%,#32903a 68%,#216d2b 100%); /* Opera 11.10+ */
|
||||||
|
background: -ms-linear-gradient(top, #379940 0%,#36983f 56%,#32903a 68%,#216d2b 100%); /* IE10+ */
|
||||||
|
background: linear-gradient(to bottom, #379940 0%,#36983f 56%,#32903a 68%,#216d2b 100%); /* W3C */
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#379940', endColorstr='#216d2b',GradientType=0 ); /* IE6-9 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#header form label,
|
||||||
|
#header label {
|
||||||
|
color: #89cc92;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header form #searchInput {
|
||||||
|
border: 1px solid #23712d;
|
||||||
|
background-color: #89cc92;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* p-cactions */
|
||||||
|
#p-cactions li {
|
||||||
|
border-bottom: 1px solid #56a05f;
|
||||||
|
background-color: #58ac64;
|
||||||
|
border-top-color: #58ac64;
|
||||||
|
}
|
||||||
|
|
||||||
|
#p-cactions li:hover {
|
||||||
|
border-top-color: #68cc76;
|
||||||
|
background-color: #68cc76;
|
||||||
|
}
|
||||||
|
|
||||||
|
#p-cactions li.selected a {
|
||||||
|
color: #455372;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NAV */
|
||||||
|
#nav {
|
||||||
|
background: #379940;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div a:hover {
|
||||||
|
background: #379940;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div a,
|
||||||
|
#nav div span.social {
|
||||||
|
background: #89cc92;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
border-top: 1px solid #fff;
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* preftoc */
|
||||||
|
#preftoc li:hover,
|
||||||
|
#preftoc li:focus,
|
||||||
|
#preftoc li.selected {
|
||||||
|
background-color: #89cc92;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fieldset */
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid #1fd931;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset fieldset {
|
||||||
|
background-color: #89cc92;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mw-line */
|
||||||
|
.mw-line-odd {
|
||||||
|
background-color: #379940;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mw-line-even {
|
||||||
|
background-color: #89cc92;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
/** These styles are configurable via configuration */
|
||||||
|
.cavendish-qr-code-mode-all #f-poweredbyico,
|
||||||
|
.cavendish-qr-code-mode-print #qrcode,
|
||||||
|
.cavendish-sidebar-searchbox #nav #p-search {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
/**
|
||||||
|
* Stylesheet for Babel extension.
|
||||||
|
*
|
||||||
|
* This should be added to your MediaWiki:Common.css page when installing this
|
||||||
|
* extension and should not be modified. You may modify the CSS code on the
|
||||||
|
* MediaWiki:Common.css page to adjust colours etc.
|
||||||
|
*
|
||||||
|
* @addtogroup Extensions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Babel wrapper layout. */
|
||||||
|
table.mw-babel-wrapper {
|
||||||
|
width: 238px;
|
||||||
|
float: right;
|
||||||
|
clear: right;
|
||||||
|
border-style: solid;
|
||||||
|
margin-right: 0;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: #99b3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Babel box layout. */
|
||||||
|
div.mw-babel-box {
|
||||||
|
float: left;
|
||||||
|
clear: left;
|
||||||
|
margin: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box table {
|
||||||
|
width: 238px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box table th {
|
||||||
|
width: 238px;
|
||||||
|
width: 45px;
|
||||||
|
height: 45px;
|
||||||
|
font-size: 14pt;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box table td {
|
||||||
|
font-size: 8pt;
|
||||||
|
padding: 4pt;
|
||||||
|
line-height: 1.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Babel box colours. */
|
||||||
|
div.mw-babel-box-0 {
|
||||||
|
border: solid #b7b7b7 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-1 {
|
||||||
|
border: solid #c0c8ff 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-2 {
|
||||||
|
border: solid #77e0e8 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-3 {
|
||||||
|
border: solid #99b3ff 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-4 {
|
||||||
|
border: solid #cc0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-5 {
|
||||||
|
border: solid #f99c99 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-N {
|
||||||
|
border: solid #6ef7a7 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-0 table th {
|
||||||
|
background-color: #b7b7b7;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-1 table th {
|
||||||
|
background-color: #c0c8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-2 table th {
|
||||||
|
background-color: #77e0e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-3 table th {
|
||||||
|
background-color: #99b3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-4 table th {
|
||||||
|
background-color: #cc0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-5 table th {
|
||||||
|
background-color: #f99c99;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-N table th{
|
||||||
|
background-color: #6ef7a7;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-0 table {
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-1 table {
|
||||||
|
background-color: #f0f8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-2 table {
|
||||||
|
background-color: #d0f8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-3 table {
|
||||||
|
background-color: #e0e8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-4 table {
|
||||||
|
background-color: #ff9;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-5 table {
|
||||||
|
background-color: #f9cbc9;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mw-babel-box-N table {
|
||||||
|
background-color: #c5fcdc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.babel-box td.babel-footer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
ol.references {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup.reference {
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: 0.8em;
|
||||||
|
vertical-align: top;
|
||||||
|
position: relative;
|
||||||
|
top: -0.2em;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reference * {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol.references > li:target {
|
||||||
|
background-color: #def;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup.reference:target {
|
||||||
|
background-color: #def;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* Hide Echo's colorful little boxes indicating how many new alerts/notices
|
||||||
|
* the user has, because:
|
||||||
|
* 1) the data is already shown on the personal tools area, and thus
|
||||||
|
* 2) these visual indicators conflict with the above and look messy since
|
||||||
|
* Cavendish does not render the icons (should it? IMHO, yes. But I was
|
||||||
|
* unable to figure out how to get it to render the Echo icons, so this'll
|
||||||
|
* have to do for the time being.)
|
||||||
|
*/
|
||||||
|
li#pt-notifications-alert .mw-echo-notifications-badge::after,
|
||||||
|
li#pt-notifications-notice .mw-echo-notifications-badge::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
div.flaggedrevs_basic,
|
||||||
|
div.flaggedrevs_quality,
|
||||||
|
div.flaggedrevs_pristine,
|
||||||
|
div.flaggedrevs_notice {
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.flaggedrevs_editnotice {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
.inputbox-element {
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
div.lqt-thread-toolbar {
|
||||||
|
right: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lqt-thread-toolbar-command-list {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lqt-talkpage-header {
|
||||||
|
border-radius: 6px;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lqt_header_content {
|
||||||
|
border-bottom-right-radius: 6px;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.lqt_watchlist_messages_notice {
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #f2dede;
|
||||||
|
border-color: #eed3d7;
|
||||||
|
color: #b94a48;
|
||||||
|
padding: 0.5em 1.5em;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
#p-personal .pBody li#pt-openidlogin {
|
||||||
|
background: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openid_large_link {
|
||||||
|
border-radius: 6px;
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openid_small_providers_block {
|
||||||
|
padding-right: 5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#provider_form_openid input {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
input.createboxInput {
|
||||||
|
margin-top: 1px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
.mandatoryFieldSpan {
|
||||||
|
border: 1px solid #8B0000;
|
||||||
|
border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
-webkit-border-radius: 3px;
|
||||||
|
background: #FFA07A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputSpan {
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
.formtable td {
|
||||||
|
padding-top: 7px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formtable th {
|
||||||
|
padding-top: 7px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pfForm div.warningbox {
|
||||||
|
border: 1px solid #ff8c00 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkboxLabel, .ui-widget {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
.mw-highlight {
|
||||||
|
padding: 1em;
|
||||||
|
margin: 1em 0;
|
||||||
|
border: 1px dashed #2fab6f;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mw-highlight ol {
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
div div#drilldown-categories-wrapper {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
table.smwtable tr.smwfooter td.sortbottom {
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.smwtable {
|
||||||
|
margin: 1em 1em 1em 0;
|
||||||
|
border: 1px #aaa solid;
|
||||||
|
border-collapse: collapse;
|
||||||
|
empty-cells: show;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.smwtable th {
|
||||||
|
background-color: #e0e9e9;
|
||||||
|
border: 1px #aaa solid;
|
||||||
|
padding: 0.2em;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.smwtable td {
|
||||||
|
border: 1px #aaa solid;
|
||||||
|
padding: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.smwtable caption {
|
||||||
|
margin-left: inherit;
|
||||||
|
margin-right: inherit;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.smwtable tr.row-odd {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
table.smwtable tr.row-odd td {
|
||||||
|
border-top: none;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.smwtable tr.row-even {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
}
|
||||||
|
table.smwtable tr.row-even td {
|
||||||
|
border-top: none;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smwttactiveinline {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smwfact {
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 2px 2px 2px #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content div.smwfact table.smwfacttable {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smwtt {
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content table.smwb-factbox,
|
||||||
|
#content table.smwb-ifactbox {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Styles for extensions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Poem Extension
|
||||||
|
*/
|
||||||
|
.poem {
|
||||||
|
margin-left: 1.5em;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poem p {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
border-left: 1px solid #ffd700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HeaderTabs */
|
||||||
|
#headertabs {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Google Maps */
|
||||||
|
.pmap {
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.google-map {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Semantic Result Formats */
|
||||||
|
/**
|
||||||
|
* As of 1 November 2020 there doesn't appear to be a ResourceLoader module we could piggyback on
|
||||||
|
* to load these styles when needed.
|
||||||
|
* @see https://github.com/SemanticMediaWiki/SemanticResultFormats/blob/master/formats/calendar/SRF_Calendar.php#L330
|
||||||
|
*/
|
||||||
|
#bodyContent table.navigation_table tr td.month_name {
|
||||||
|
font-size: 18pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bodyContent table.month_calendar tr.weekdays {
|
||||||
|
background: #e0e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bodyContent table.month_calendar td.today div.day {
|
||||||
|
background: #e0e9e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bodyContent table.month_calendar td.weekend_day div.day {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bodyContent .srf-datatables select {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4sq */
|
||||||
|
table .tips-4sq blockquote {
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-left: 20px;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* yelp */
|
||||||
|
table .yelp-reviews blockquote {
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Social Sidebar WeCoWi */
|
||||||
|
#nav div li span.social {
|
||||||
|
padding-bottom: 6px;
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div li#buffer span.social {
|
||||||
|
padding-left: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div li#facebook span span {
|
||||||
|
margin-left: -10px;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div li#facebook span.social {
|
||||||
|
height: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav div li#twitter span.social iframe {
|
||||||
|
margin-left: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav a.twitter-share-button {
|
||||||
|
font-weight: normal;
|
||||||
|
border: none;
|
||||||
|
padding: 0 0 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav li#google span.social,
|
||||||
|
#nav li#flattr span.social {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
div.wikiEditor-ui div.section {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikiEditor-ui div.wikiEditor-ui-top {
|
||||||
|
font-size: 8.5pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.wikiEditor-ui div.wikiEditor-ui-tabs div {
|
||||||
|
font-size: 9pt;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Comfortaa:wght@600;700&family=Quicksand:wght@400;500&display=swap');
|
||||||
|
|
||||||
|
#header #site-logo-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header #site-logo-link:hover,
|
||||||
|
#header #site-logo-link:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header #site-logo-link img {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
display: block;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#site-name {
|
||||||
|
font-family: 'Comfortaa', sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
color: #ffffff;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 526 B |
|
After Width: | Height: | Size: 50 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 102 B |
|
After Width: | Height: | Size: 103 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 47 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 791 B |
|
After Width: | Height: | Size: 248 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 281 B |
|
After Width: | Height: | Size: 163 B |
|
After Width: | Height: | Size: 266 B |
|
After Width: | Height: | Size: 932 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
|
@ -0,0 +1,10 @@
|
||||||
|
#editpage-copywarn {
|
||||||
|
margin-top: 2em;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
input#wpSummary {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* the auto-generated edit comments */
|
||||||
|
.autocomment {
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagehistory span.user {
|
||||||
|
margin-left: 1.4em;
|
||||||
|
margin-right: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagehistory span.minor {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagehistory li {
|
||||||
|
border: 1px solid #fff;
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagehistory li:focus,
|
||||||
|
#pagehistory li:hover {
|
||||||
|
box-shadow: 0 0 2px inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pagehistory li.selected {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px dashed #aaa;
|
||||||
|
border-radius: 6px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.updatedmarker {
|
||||||
|
/* color: black; */
|
||||||
|
color: #00ff00;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
ul#filetoc {
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 95%;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filetoc li {
|
||||||
|
display: inline;
|
||||||
|
list-style-type: none;
|
||||||
|
padding-right: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.filehistory {
|
||||||
|
overflow: scroll;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.mw_metadata {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
.redirectText {
|
||||||
|
font-size: 150%;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
table.diff {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.diff-otitle {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.diff-ntitle {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.diff-addedline {
|
||||||
|
background: #cfc;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.diff-deletedline {
|
||||||
|
background: #ffa;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.diff-context {
|
||||||
|
background: #eee;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.diffchange {
|
||||||
|
color: #f00;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
table.gallery {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
margin: 2px;
|
||||||
|
padding: 2px;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.gallery tr {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.gallery td {
|
||||||
|
vertical-align: top;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: solid 2px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.gallerybox {
|
||||||
|
margin: 2px;
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.gallerybox div.thumb {
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.gallerytext {
|
||||||
|
font-size: 94%;
|
||||||
|
padding: 2px 4px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
#content table.mw-enhanced-rc {
|
||||||
|
margin-bottom: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.mw-enhanced-rc {
|
||||||
|
font-family: Verdana, "DejaVu Sans", sans-serif;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.mw-enhanced-rc th,
|
||||||
|
table.mw-enhanced-rc td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.mw-enhanced-rc .newpage,
|
||||||
|
td.mw-enhanced-rc .minoredit,
|
||||||
|
td.mw-enhanced-rc .botedit {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
table#sv-ext,
|
||||||
|
table#sv-hooks,
|
||||||
|
table#sv-software,
|
||||||
|
table#mw-version-entrypoints-table,
|
||||||
|
.mw-special-Version #mw-content-text table {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sv-ext td,
|
||||||
|
#sv-hooks td,
|
||||||
|
#sv-software td,
|
||||||
|
#sv-ext th,
|
||||||
|
#sv-hooks th,
|
||||||
|
#sv-software th,
|
||||||
|
.mw-special-Version #bodyContent td,
|
||||||
|
.mw-special-Version #bodyContent th {
|
||||||
|
border: 1px solid #a0a0a0;
|
||||||
|
padding: 0.1em 0.2em 0.1em 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sv-ext th,
|
||||||
|
#sv-hooks th,
|
||||||
|
#sv-software th,
|
||||||
|
.mw-special-Version #bodyContent th {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
color: #000;
|
||||||
|
padding: 0.1em 0.2em 0.1em 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.sv-space {
|
||||||
|
height: 0.8em;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.sv-space td {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* Table of Contents */
|
||||||
|
#toc,
|
||||||
|
.toc,
|
||||||
|
.mw-warning {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 9pt;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 1px 1px 1px grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toc,
|
||||||
|
.toc {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toctitle h2 {
|
||||||
|
display: inline;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 9.5pt;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toc #toctitle,
|
||||||
|
.toc #toctitle,
|
||||||
|
#toc .toctitle,
|
||||||
|
.toc .toctitle {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toc ul,
|
||||||
|
.toc ul {
|
||||||
|
list-style-type: none;
|
||||||
|
list-style-image: none;
|
||||||
|
margin-left: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toc ul ul,
|
||||||
|
.toc ul ul {
|
||||||
|
margin: 0 0 0 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toctitle .toctoggle {
|
||||||
|
font-size: 8pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toccolours {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
font-size: 95%;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* Stylesheet for printing */
|
||||||
|
body {
|
||||||
|
margin-left: 5em;
|
||||||
|
margin-right: 5em;
|
||||||
|
font-size: 11pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#p-personal,
|
||||||
|
#side,
|
||||||
|
#header,
|
||||||
|
#skin-info,
|
||||||
|
#f-numberofwatchingusers,
|
||||||
|
#f-viewcount,
|
||||||
|
#f-privacy,
|
||||||
|
#f-about,
|
||||||
|
#f-disclaimer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.f-iconsection #f-copyrightico {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#qrcode {
|
||||||
|
display: block;
|
||||||
|
margin-left: 10px;
|
||||||
|
text-align:right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer #f-list li {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer li {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#catlinks {
|
||||||
|
border-top: 1px solid #aaa;
|
||||||
|
margin-top: 1em;
|
||||||
|
padding-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#catlinks ul li {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.float-right,
|
||||||
|
table.floatright,
|
||||||
|
div.float-right,
|
||||||
|
div.floatright {
|
||||||
|
clear: right;
|
||||||
|
float: right;
|
||||||
|
margin-left: 0.7em;
|
||||||
|
margin-right: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.float-left,
|
||||||
|
table.floatleft,
|
||||||
|
div.float-left,
|
||||||
|
div.floatleft {
|
||||||
|
clear: left;
|
||||||
|
float: left;
|
||||||
|
margin-right: 0.7em;
|
||||||
|
margin-left: 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
table p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,213 @@
|
||||||
|
{
|
||||||
|
"name": "Cavendish",
|
||||||
|
"author": [
|
||||||
|
"Daniel Schuba",
|
||||||
|
"Jack Phoenix",
|
||||||
|
"Samantha Nguyen",
|
||||||
|
"Jon Robson"
|
||||||
|
],
|
||||||
|
"version": "3.0.0",
|
||||||
|
"@note": "Remember to update the version number in CavendishTemplate.php, too, since it's passed to the \"cavendish-skin-info\" i18n message!",
|
||||||
|
"url": "https://www.mediawiki.org/wiki/Skin:Cavendish",
|
||||||
|
"descriptionmsg": "cavendish-desc",
|
||||||
|
"namemsg": "skinname-cavendish",
|
||||||
|
"license-name": "GPL-2.0-or-later",
|
||||||
|
"type": "skin",
|
||||||
|
"requires": {
|
||||||
|
"MediaWiki": ">= 1.41.0"
|
||||||
|
},
|
||||||
|
"ConfigRegistry": {
|
||||||
|
"cavendish": "MediaWiki\\Config\\GlobalVarConfig::newInstance"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"CavendishQRUrlAdd": "?pk_campaign=qr-code",
|
||||||
|
"CavendishQRCode": false,
|
||||||
|
"CavendishQRCodeMode": "all",
|
||||||
|
"CavendishSiteWidth": false,
|
||||||
|
"CavendishSidebarSearchbox": false
|
||||||
|
},
|
||||||
|
"ValidSkinNames": {
|
||||||
|
"cavendish": {
|
||||||
|
"class": "SkinTemplate",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "cavendish",
|
||||||
|
"bodyOnly": true,
|
||||||
|
"template": "CavendishTemplate",
|
||||||
|
"styles": [
|
||||||
|
"skins.cavendish",
|
||||||
|
"skins.cavendish.blue"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"cavendish-brown": {
|
||||||
|
"class": "SkinTemplate",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "cavendish-brown",
|
||||||
|
"template": "CavendishTemplate",
|
||||||
|
"styles": [
|
||||||
|
"skins.cavendish",
|
||||||
|
"skins.cavendish.brown"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"cavendish-green": {
|
||||||
|
"class": "SkinTemplate",
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "cavendish-green",
|
||||||
|
"template": "CavendishTemplate",
|
||||||
|
"styles": [
|
||||||
|
"skins.cavendish",
|
||||||
|
"skins.cavendish.green"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MessagesDirs": {
|
||||||
|
"Cavendish": [
|
||||||
|
"i18n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"ResourceModules": {
|
||||||
|
"skins.cavendish": {
|
||||||
|
"class": "MediaWiki\\ResourceLoader\\SkinModule",
|
||||||
|
"features": [
|
||||||
|
"elements",
|
||||||
|
"interface",
|
||||||
|
"logo",
|
||||||
|
"content-links",
|
||||||
|
"content-media",
|
||||||
|
"interface-message-box",
|
||||||
|
"interface-category",
|
||||||
|
"content-tables",
|
||||||
|
"i18n-ordered-lists",
|
||||||
|
"i18n-all-lists-margins",
|
||||||
|
"i18n-headings"
|
||||||
|
],
|
||||||
|
"styles": {
|
||||||
|
"resources/cavendish.css": {
|
||||||
|
"media": "screen"
|
||||||
|
},
|
||||||
|
"resources/header.css": {
|
||||||
|
"media": "screen"
|
||||||
|
},
|
||||||
|
"resources/print.css": {
|
||||||
|
"media": "print"
|
||||||
|
},
|
||||||
|
"resources/dynamic.css": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skins.cavendish.extensions": {
|
||||||
|
"styles": {
|
||||||
|
"resources/extensions/extensions.css": {
|
||||||
|
"media": "screen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skins.cavendish.blue": {
|
||||||
|
"styles": {
|
||||||
|
"resources/colors/blue.css": {
|
||||||
|
"media": "screen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skins.cavendish.brown": {
|
||||||
|
"styles": {
|
||||||
|
"resources/colors/brown.css": {
|
||||||
|
"media": "screen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skins.cavendish.green": {
|
||||||
|
"styles": {
|
||||||
|
"resources/colors/green.css": {
|
||||||
|
"media": "screen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ResourceFileModulePaths": {
|
||||||
|
"localBasePath": "",
|
||||||
|
"remoteSkinPath": "Cavendish"
|
||||||
|
},
|
||||||
|
"AutoloadClasses": {
|
||||||
|
"CavendishTemplate": "CavendishTemplate.php"
|
||||||
|
},
|
||||||
|
"ResourceModuleSkinStyles": {
|
||||||
|
"cavendish-brown": {
|
||||||
|
"+ext.babel": "resources/extensions/babel.css",
|
||||||
|
"+ext.cite.style": "resources/extensions/ext.cite.style.css",
|
||||||
|
"+ext.echo.styles.badge": "resources/extensions/ext.echo.styles.badge.css",
|
||||||
|
"+ext.flaggedRevs.basic": "resources/extensions/ext.flaggedRevs.basic.css",
|
||||||
|
"+ext.inputBox.styles": "resources/extensions/ext.inputBox.styles.css",
|
||||||
|
"+ext.liquidThreads": "resources/extensions/ext.liquidThreads.css",
|
||||||
|
"+ext.openid.plain": "resources/extensions/ext.openid.plain.css",
|
||||||
|
"+ext.pageforms.main": "resources/extensions/ext.pageforms.main.css",
|
||||||
|
"+ext.pygments": "resources/extensions/ext.pygments.css",
|
||||||
|
"+ext.semanticdrilldown.main": "resources/extensions/ext.semanticdrilldown.main.css",
|
||||||
|
"+ext.smw.style": "resources/extensions/ext.smw.style.css",
|
||||||
|
"+jquery.wikiEditor": "resources/extensions/jquery.wikiEditor.css",
|
||||||
|
"+mediawiki.action.edit": "resources/mediawiki/action.edit.css",
|
||||||
|
"+mediawiki.action.history.styles": "resources/mediawiki/action.history.styles.css",
|
||||||
|
"+mediawiki.action.view.filepage": "resources/mediawiki/action.view.filepage.css",
|
||||||
|
"+mediawiki.action.view.redirectPage": "resources/mediawiki/action.view.redirectPage.css",
|
||||||
|
"+mediawiki.diff.styles": "resources/mediawiki/diff.styles.css",
|
||||||
|
"+mediawiki.page.gallery.styles": "resources/mediawiki/page.gallery.styles.css",
|
||||||
|
"+mediawiki.special.changeslist.enhanced": "resources/mediawiki/special.changeslist.enhanced.css",
|
||||||
|
"+mediawiki.special.version": "resources/mediawiki/special.version.css",
|
||||||
|
"+mediawiki.toc": "resources/mediawiki/toc.css"
|
||||||
|
},
|
||||||
|
"cavendish-green": {
|
||||||
|
"+ext.babel": "resources/extensions/babel.css",
|
||||||
|
"+ext.cite.style": "resources/extensions/ext.cite.style.css",
|
||||||
|
"+ext.echo.styles.badge": "resources/extensions/ext.echo.styles.badge.css",
|
||||||
|
"+ext.flaggedRevs.basic": "resources/extensions/ext.flaggedRevs.basic.css",
|
||||||
|
"+ext.inputBox.styles": "resources/extensions/ext.inputBox.styles.css",
|
||||||
|
"+ext.liquidThreads": "resources/extensions/ext.liquidThreads.css",
|
||||||
|
"+ext.openid.plain": "resources/extensions/ext.openid.plain.css",
|
||||||
|
"+ext.pageforms.main": "resources/extensions/ext.pageforms.main.css",
|
||||||
|
"+ext.pygments": "resources/extensions/ext.pygments.css",
|
||||||
|
"+ext.semanticdrilldown.main": "resources/extensions/ext.semanticdrilldown.main.css",
|
||||||
|
"+ext.smw.style": "resources/extensions/ext.smw.style.css",
|
||||||
|
"+jquery.wikiEditor": "resources/extensions/jquery.wikiEditor.css",
|
||||||
|
"+mediawiki.action.edit": "resources/mediawiki/action.edit.css",
|
||||||
|
"+mediawiki.action.history.styles": "resources/mediawiki/action.history.styles.css",
|
||||||
|
"+mediawiki.action.view.filepage": "resources/mediawiki/action.view.filepage.css",
|
||||||
|
"+mediawiki.action.view.redirectPage": "resources/mediawiki/action.view.redirectPage.css",
|
||||||
|
"+mediawiki.diff.styles": "resources/mediawiki/diff.styles.css",
|
||||||
|
"+mediawiki.page.gallery.styles": "resources/mediawiki/page.gallery.styles.css",
|
||||||
|
"+mediawiki.special.changeslist.enhanced": "resources/mediawiki/special.changeslist.enhanced.css",
|
||||||
|
"+mediawiki.special.version": "resources/mediawiki/special.version.css",
|
||||||
|
"+mediawiki.toc": "resources/mediawiki/toc.css"
|
||||||
|
},
|
||||||
|
"cavendish": {
|
||||||
|
"+ext.babel": "resources/extensions/babel.css",
|
||||||
|
"+ext.cite.style": "resources/extensions/ext.cite.style.css",
|
||||||
|
"+ext.echo.styles.badge": "resources/extensions/ext.echo.styles.badge.css",
|
||||||
|
"+ext.flaggedRevs.basic": "resources/extensions/ext.flaggedRevs.basic.css",
|
||||||
|
"+ext.inputBox.styles": "resources/extensions/ext.inputBox.styles.css",
|
||||||
|
"+ext.liquidThreads": "resources/extensions/ext.liquidThreads.css",
|
||||||
|
"+ext.openid.plain": "resources/extensions/ext.openid.plain.css",
|
||||||
|
"+ext.pageforms.main": "resources/extensions/ext.pageforms.main.css",
|
||||||
|
"+ext.pygments": "resources/extensions/ext.pygments.css",
|
||||||
|
"+ext.semanticdrilldown.main": "resources/extensions/ext.semanticdrilldown.main.css",
|
||||||
|
"+ext.smw.style": "resources/extensions/ext.smw.style.css",
|
||||||
|
"+jquery.wikiEditor": "resources/extensions/jquery.wikiEditor.css",
|
||||||
|
"+mediawiki.action.edit": "resources/mediawiki/action.edit.css",
|
||||||
|
"+mediawiki.action.history.styles": "resources/mediawiki/action.history.styles.css",
|
||||||
|
"+mediawiki.action.view.filepage": "resources/mediawiki/action.view.filepage.css",
|
||||||
|
"+mediawiki.action.view.redirectPage": "resources/mediawiki/action.view.redirectPage.css",
|
||||||
|
"+mediawiki.diff.styles": "resources/mediawiki/diff.styles.css",
|
||||||
|
"+mediawiki.page.gallery.styles": "resources/mediawiki/page.gallery.styles.css",
|
||||||
|
"+mediawiki.special.changeslist.enhanced": "resources/mediawiki/special.changeslist.enhanced.css",
|
||||||
|
"+mediawiki.special.version": "resources/mediawiki/special.version.css",
|
||||||
|
"+mediawiki.toc": "resources/mediawiki/toc.css"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"manifest_version": 1
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,10 @@
|
||||||
"dev": "pwsh -ExecutionPolicy Bypass -File ./scripts/dev.ps1",
|
"dev": "pwsh -ExecutionPolicy Bypass -File ./scripts/dev.ps1",
|
||||||
"a11y:pa11y": "pa11y-ci --config ./tests/accessibility/pa11y.config.json",
|
"a11y:pa11y": "pa11y-ci --config ./tests/accessibility/pa11y.config.json",
|
||||||
"a11y:lighthouse": "lhci autorun --config=./tests/accessibility/lighthouserc.json",
|
"a11y:lighthouse": "lhci autorun --config=./tests/accessibility/lighthouserc.json",
|
||||||
"a11y:all": "npm run a11y:pa11y && npm run a11y:lighthouse"
|
"a11y:all": "npm run a11y:pa11y && npm run a11y:lighthouse",
|
||||||
|
"deploy": "pwsh -ExecutionPolicy Bypass -File ./scripts/deploy.ps1 -Mode skin",
|
||||||
|
"deploy:all": "pwsh -ExecutionPolicy Bypass -File ./scripts/deploy.ps1 -Mode all",
|
||||||
|
"deploy:initial": "pwsh -ExecutionPolicy Bypass -File ./scripts/deploy.ps1 -Mode initial"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lhci/cli": "^0.14.0",
|
"@lhci/cli": "^0.14.0",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Deployt GPLX MediaWiki auf den Bitpalast-Server.
|
||||||
|
|
||||||
|
.PARAMETER Mode
|
||||||
|
skin - Cavendish-Skin synchronisieren (Standard, schnell)
|
||||||
|
templates - Wiki-Seiten-Vorlagen synchronisieren
|
||||||
|
all - Skin + Templates
|
||||||
|
initial - Erstinstallation: gesamten MediaWiki-Core übertragen
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\deploy.ps1 # Skin deployen
|
||||||
|
.\deploy.ps1 -Mode all # Skin + Templates
|
||||||
|
.\deploy.ps1 -Mode initial
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[ValidateSet('skin', 'templates', 'all', 'initial')]
|
||||||
|
[string]$Mode = 'skin'
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
# === Config laden ===
|
||||||
|
$envFile = Join-Path $PSScriptRoot '..' '.deploy.env'
|
||||||
|
if (-not (Test-Path $envFile)) {
|
||||||
|
Write-Error @"
|
||||||
|
.deploy.env nicht gefunden.
|
||||||
|
Kopiere .deploy.example.env zu .deploy.env und trage deine Zugangsdaten ein.
|
||||||
|
"@
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Get-Content $envFile | ForEach-Object {
|
||||||
|
if ($_ -match '^\s*([^#][^=]+)=(.*)$') {
|
||||||
|
[System.Environment]::SetEnvironmentVariable($Matches[1].Trim(), $Matches[2].Trim(), 'Process')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$deployHost = $env:DEPLOY_HOST
|
||||||
|
$deployUser = $env:DEPLOY_USER
|
||||||
|
$mwPath = $env:DEPLOY_MW_PATH
|
||||||
|
$projectPath = $env:DEPLOY_PROJECT_PATH
|
||||||
|
$target = "${deployUser}@${deployHost}"
|
||||||
|
|
||||||
|
foreach ($var in @('DEPLOY_HOST','DEPLOY_USER','DEPLOY_MW_PATH')) {
|
||||||
|
if (-not [System.Environment]::GetEnvironmentVariable($var, 'Process')) {
|
||||||
|
Write-Error "$var ist nicht in .deploy.env gesetzt."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# === WSL rsync oder scp ===
|
||||||
|
$hasWsl = $null -ne (Get-Command 'wsl' -ErrorAction SilentlyContinue)
|
||||||
|
|
||||||
|
function ConvertTo-WslPath([string]$winPath) {
|
||||||
|
$abs = [System.IO.Path]::GetFullPath($winPath)
|
||||||
|
$drive = $abs.Substring(0, 1).ToLower()
|
||||||
|
$rest = $abs.Substring(2).Replace('\', '/')
|
||||||
|
return "/mnt/$drive$rest"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sync-Dir([string]$localDir, [string]$remoteDir, [bool]$delete = $false) {
|
||||||
|
Write-Host " $localDir" -ForegroundColor DarkGray
|
||||||
|
Write-Host " -> ${target}:${remoteDir}" -ForegroundColor DarkGray
|
||||||
|
|
||||||
|
if ($hasWsl) {
|
||||||
|
$wslSrc = (ConvertTo-WslPath $localDir) + '/'
|
||||||
|
$rsyncArgs = @('-az', '--progress')
|
||||||
|
if ($delete) { $rsyncArgs += '--delete' }
|
||||||
|
$rsyncArgs += $wslSrc
|
||||||
|
$rsyncArgs += "${target}:${remoteDir}/"
|
||||||
|
wsl rsync @rsyncArgs
|
||||||
|
} else {
|
||||||
|
# Fallback: scp (kein automatisches Loeschen von Remotedateien)
|
||||||
|
Write-Warning "WSL nicht gefunden – nutze scp. Geloeschte lokale Dateien bleiben auf dem Server."
|
||||||
|
ssh $target "mkdir -p '$remoteDir'"
|
||||||
|
scp -r "${localDir}\." "${target}:${remoteDir}/"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Error "Uebertragung fehlgeschlagen (Exit $LASTEXITCODE)."
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$repoRoot = Split-Path $PSScriptRoot
|
||||||
|
|
||||||
|
# === Deploy-Modi ===
|
||||||
|
switch ($Mode) {
|
||||||
|
|
||||||
|
'skin' {
|
||||||
|
Write-Host "Deploye Cavendish-Skin..." -ForegroundColor Cyan
|
||||||
|
Sync-Dir "$repoRoot\mediawiki\skins\Cavendish" "$mwPath/skins/Cavendish" -delete $true
|
||||||
|
Write-Host "Fertig." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
'templates' {
|
||||||
|
if (-not $projectPath) {
|
||||||
|
Write-Error "DEPLOY_PROJECT_PATH muss in .deploy.env gesetzt sein."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Host "Deploye Wiki-Templates..." -ForegroundColor Cyan
|
||||||
|
Sync-Dir "$repoRoot\scripts\templates" "$projectPath/scripts/templates"
|
||||||
|
Write-Host "Fertig." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
'all' {
|
||||||
|
Write-Host "Deploye Skin + Templates..." -ForegroundColor Cyan
|
||||||
|
Sync-Dir "$repoRoot\mediawiki\skins\Cavendish" "$mwPath/skins/Cavendish" -delete $true
|
||||||
|
if ($projectPath) {
|
||||||
|
Sync-Dir "$repoRoot\scripts\templates" "$projectPath/scripts/templates"
|
||||||
|
}
|
||||||
|
Write-Host "Fertig." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
'initial' {
|
||||||
|
Write-Host "Erstinstallation – uebertraege MediaWiki-Core..." -ForegroundColor Yellow
|
||||||
|
Write-Host "Das kann einige Minuten dauern." -ForegroundColor DarkGray
|
||||||
|
|
||||||
|
$excludes = @(
|
||||||
|
'--exclude=.git',
|
||||||
|
'--exclude=vendor/',
|
||||||
|
'--exclude=images/',
|
||||||
|
'--exclude=cache/',
|
||||||
|
'--exclude=LocalSettings.php'
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($hasWsl) {
|
||||||
|
$wslSrc = (ConvertTo-WslPath "$repoRoot\mediawiki") + '/'
|
||||||
|
$rsyncArgs = @('-az', '--progress') + $excludes + @($wslSrc, "${target}:${mwPath}/")
|
||||||
|
wsl rsync @rsyncArgs
|
||||||
|
} else {
|
||||||
|
Write-Warning "Fuer die Erstinstallation wird WSL empfohlen (grosse Datenmenge)."
|
||||||
|
Write-Warning "Alternative: WinSCP GUI verwenden oder WSL installieren."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Erstinstallation abgeschlossen." -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Naechste Schritte auf dem Server:" -ForegroundColor Yellow
|
||||||
|
Write-Host " 1. LocalSettings.php anlegen:"
|
||||||
|
Write-Host " Vorlage: mediawiki/LocalSettings.production.example.php"
|
||||||
|
Write-Host " 2. Composer-Abhaengigkeiten installieren:"
|
||||||
|
Write-Host " cd $mwPath && composer install --no-dev"
|
||||||
|
Write-Host " 3. Datenbank einrichten:"
|
||||||
|
Write-Host " php maintenance/run.php install ..."
|
||||||
|
Write-Host " oder: Dump importieren mit mysql -u user -p dbname < dump.sql"
|
||||||
|
Write-Host " 4. SMW initialisieren:"
|
||||||
|
Write-Host " php maintenance/run.php setupStore"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
Pages in this category cover clinical evaluation, clinical performance, post-market clinical follow-up (PMCF), and post-market performance follow-up (PMPF).
|
||||||
|
|
||||||
|
== Pages in this category ==
|
||||||
|
|
||||||
|
{{#ask: [[Category:Clinical]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Scope = Scope
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
}}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
Pages in this category cover regulatory documents and references in the In Vitro Diagnostics (IVD) scope.
|
||||||
|
|
||||||
|
== Documents ==
|
||||||
|
|
||||||
|
{{#ask: [[Category:In Vitro Diagnostics]] [[Status::+]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Status = Status
|
||||||
|
| ?Area of validity = Region
|
||||||
|
| ?Version = Version
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
| sort=Status
|
||||||
|
}}
|
||||||
|
|
||||||
|
== Browse by topic ==
|
||||||
|
|
||||||
|
* [[:Category:Clinical|Clinical]]
|
||||||
|
* [[:Category:Post-Market Surveillance|Post-Market Surveillance]]
|
||||||
|
* [[:Category:Labelling|Labelling]]
|
||||||
|
* [[:Category:Traceability|Traceability]]
|
||||||
|
* [[:Category:Performance Evaluation|Performance Evaluation]]
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
Pages in this category cover labelling requirements, UDI carriers, and packaging obligations.
|
||||||
|
|
||||||
|
== Pages in this category ==
|
||||||
|
|
||||||
|
{{#ask: [[Category:Labelling]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Scope = Scope
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
}}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
Pages in this category cover regulatory documents and references in the Medical Devices (MD) scope.
|
||||||
|
|
||||||
|
== Documents ==
|
||||||
|
|
||||||
|
{{#ask: [[Category:Medical Devices]] [[Status::+]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Status = Status
|
||||||
|
| ?Area of validity = Region
|
||||||
|
| ?Version = Version
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
| sort=Status
|
||||||
|
}}
|
||||||
|
|
||||||
|
== Browse by topic ==
|
||||||
|
|
||||||
|
* [[:Category:Clinical|Clinical]]
|
||||||
|
* [[:Category:Post-Market Surveillance|Post-Market Surveillance]]
|
||||||
|
* [[:Category:Labelling|Labelling]]
|
||||||
|
* [[:Category:Traceability|Traceability]]
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
Pages in this category cover post-market surveillance (PMS), post-market clinical follow-up (PMCF), post-market performance follow-up (PMPF), and periodic safety update reports (PSUR).
|
||||||
|
|
||||||
|
== Pages in this category ==
|
||||||
|
|
||||||
|
{{#ask: [[Category:Post-Market Surveillance]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Scope = Scope
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
}}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
This page lists all regulatory documents in this wiki. Use the sections below to browse by status or scope.
|
||||||
|
|
||||||
|
== Current documents ==
|
||||||
|
|
||||||
|
{{#ask: [[Status::Current]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Scope = Scope
|
||||||
|
| ?Area of validity = Region
|
||||||
|
| ?Document type = Type
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=100
|
||||||
|
| sort=Scope
|
||||||
|
}}
|
||||||
|
|
||||||
|
== Grouped by scope ==
|
||||||
|
|
||||||
|
=== Medical Devices (MD) ===
|
||||||
|
|
||||||
|
{{#ask: [[Scope::~*MD*]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Status = Status
|
||||||
|
| ?Area of validity = Region
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
}}
|
||||||
|
|
||||||
|
=== In Vitro Diagnostics (IVD) ===
|
||||||
|
|
||||||
|
{{#ask: [[Scope::~*IVD*]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Status = Status
|
||||||
|
| ?Area of validity = Region
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
}}
|
||||||
|
|
||||||
|
=== GMP / PV / NIS ===
|
||||||
|
|
||||||
|
{{#ask: [[Scope::~*GMP*]] OR [[Scope::~*PV*]] OR [[Scope::~*NIS*]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Scope = Scope
|
||||||
|
| ?Status = Status
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
}}
|
||||||
|
|
||||||
|
== Draft and not yet promulgated ==
|
||||||
|
|
||||||
|
{{#ask: [[Status::Draft]] OR [[Status::Final not promulgated]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Scope = Scope
|
||||||
|
| ?Area of validity = Region
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
}}
|
||||||
|
|
||||||
|
== Superseded ==
|
||||||
|
|
||||||
|
{{#ask: [[Status::Superseded]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Scope = Scope
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=50
|
||||||
|
}}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
{{RegDocument
|
||||||
|
| area_of_validity = EU
|
||||||
|
| scope = IVD
|
||||||
|
| document_type = Regulation
|
||||||
|
| name = In Vitro Diagnostic Medical Devices Regulation (EU) 2017/746
|
||||||
|
| version = 2017/746, amended by 2022/1107
|
||||||
|
| source = https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R0746
|
||||||
|
| language = EN, DE, FR (all EU official languages)
|
||||||
|
| status = Current
|
||||||
|
| restricted_access = No
|
||||||
|
}}
|
||||||
|
|
||||||
|
The In Vitro Diagnostic Medical Devices Regulation (IVDR) 2017/746 replaces the former IVD Directive (IVDD 98/79/EC). It introduces a significantly stricter framework for in vitro diagnostic medical devices, including reclassification of the majority of IVDs into higher risk classes requiring Notified Body involvement.
|
||||||
|
|
||||||
|
Full application started on 26 May 2022. The amendment 2022/1107 introduced a phased transition for legacy devices based on device class and Notified Body capacity.
|
||||||
|
|
||||||
|
== Key references ==
|
||||||
|
|
||||||
|
{| class="wikitable" style="width:100%;"
|
||||||
|
! Topic / Keyword(s) !! Category / Chapter !! Scope !! Linked document !! Description
|
||||||
|
{{Reference
|
||||||
|
| topic = Post-market performance follow-up, PMPF
|
||||||
|
| category = Clinical
|
||||||
|
| scope = IVD
|
||||||
|
| linked_document = [[IVDR (EU) 2017/746 – Articles 78–81 & Annex XIII Part B: Post-Market Performance Follow-Up]]
|
||||||
|
| description = Articles 78–81 and Annex XIII Part B define the mandatory post-market performance follow-up (PMPF) system, equivalent to PMCF under MDR.
|
||||||
|
}}
|
||||||
|
{{Reference
|
||||||
|
| topic = Unique Device Identification, UDI, Traceability
|
||||||
|
| category = Labelling
|
||||||
|
| scope = IVD
|
||||||
|
| linked_document = [[IVDR (EU) 2017/746 – Articles 24–26 & Annex VI: UDI]]
|
||||||
|
| description = Articles 24–26 and Annex VI establish the UDI system for IVDs, aligned with the MDR UDI framework.
|
||||||
|
}}
|
||||||
|
{{Reference
|
||||||
|
| topic = Performance evaluation, Scientific validity
|
||||||
|
| category = Clinical
|
||||||
|
| scope = IVD
|
||||||
|
| linked_document = [[IVDR (EU) 2017/746 – Article 56 & Annex XIII Part A: Performance Evaluation]]
|
||||||
|
| description = Article 56 and Annex XIII Part A define performance evaluation requirements, including analytical performance, clinical performance, and scientific validity.
|
||||||
|
}}
|
||||||
|
|}
|
||||||
|
|
||||||
|
[[Category:In Vitro Diagnostics]]
|
||||||
|
[[Category:EU Regulation]]
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
This wiki is a structured reference database for regulatory documents in the medical devices, in vitro diagnostics, and pharmaceutical sectors. Each document is stored with standardized metadata (scope, validity status, region, official source) and linked to individual pages for its key articles, annexes, and provisions, organized by topic.
|
||||||
|
|
||||||
|
The database currently covers regulations, directives, and guidelines in the MD, IVD, GMP, PV, and NIS scopes. Cross-references between equivalent provisions in different regulations are maintained explicitly, for example between MDR and IVDR requirements on post-market surveillance or UDI.
|
||||||
|
|
||||||
|
Structured queries are available on the [[Document_Index|Document Index]] and on each category page. Use [[Special:Ask|Special:Ask]] for custom queries across any combination of scope, status, region, or topic.
|
||||||
|
|
||||||
|
All registered users can contribute. New pages require reviewer approval before becoming publicly visible.
|
||||||
|
|
||||||
|
== Quick navigation ==
|
||||||
|
|
||||||
|
{| style="width:100%; border-collapse:collapse;"
|
||||||
|
|-
|
||||||
|
| style="width:33%; vertical-align:top; padding:0 1em 1em 0;" |
|
||||||
|
=== By document ===
|
||||||
|
* [[Document_Index|All documents]]
|
||||||
|
* [[Special:RecentChanges|Recent changes]]
|
||||||
|
* [[Special:Ask|Custom query]]
|
||||||
|
|
||||||
|
| style="width:33%; vertical-align:top; padding:0 1em 1em 0;" |
|
||||||
|
=== By scope ===
|
||||||
|
* [[:Category:Medical Devices|Medical Devices (MD)]]
|
||||||
|
* [[:Category:In Vitro Diagnostics|In Vitro Diagnostics (IVD)]]
|
||||||
|
|
||||||
|
| style="width:33%; vertical-align:top; padding:0 1em 1em 0;" |
|
||||||
|
=== By topic ===
|
||||||
|
* [[:Category:Clinical|Clinical]]
|
||||||
|
* [[:Category:Post-Market Surveillance|Post-Market Surveillance]]
|
||||||
|
* [[:Category:Labelling|Labelling]]
|
||||||
|
* [[:Category:Traceability|Traceability]]
|
||||||
|
|}
|
||||||
|
|
||||||
|
== Current documents ==
|
||||||
|
|
||||||
|
{{#ask: [[Status::Current]]
|
||||||
|
| ?Document name = Name
|
||||||
|
| ?Scope = Scope
|
||||||
|
| ?Area of validity = Region
|
||||||
|
| format=table
|
||||||
|
| headers=show
|
||||||
|
| limit=10
|
||||||
|
| sort=Scope
|
||||||
|
}}
|
||||||
|
|
||||||
|
[[Document_Index|View all documents →]]
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
PROPERTIES_BATCH
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
{{RegDocument
|
||||||
|
| area_of_validity = EU
|
||||||
|
| scope = IVD
|
||||||
|
| document_type = Regulation – Article Reference
|
||||||
|
| name = IVDR (EU) 2017/746 – Articles 78–81 & Annex XIII Part B: Post-Market Performance Follow-Up
|
||||||
|
| version = 2017/746
|
||||||
|
| source = https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R0746#d1e6179-1-1
|
||||||
|
| language = EN, DE, FR
|
||||||
|
| status = Current
|
||||||
|
| restricted_access = No
|
||||||
|
}}
|
||||||
|
|
||||||
|
Articles 78 to 81 and Annex XIII Part B of the IVDR establish the mandatory post-market performance follow-up (PMPF) system for IVD manufacturers. PMPF is the IVD equivalent of PMCF under the MDR.
|
||||||
|
|
||||||
|
== Summary ==
|
||||||
|
|
||||||
|
Manufacturers must proactively collect and evaluate data from devices already on the market to confirm safety, performance, and scientific validity throughout the device lifetime.
|
||||||
|
|
||||||
|
Key obligations:
|
||||||
|
|
||||||
|
* Article 78 – General post-market surveillance requirements
|
||||||
|
* Article 79 – Post-market surveillance plan
|
||||||
|
* Article 80 – Post-market surveillance report (Class A and B devices)
|
||||||
|
* Article 81 – Periodic Safety Update Report (PSUR, Class C and D devices)
|
||||||
|
* Annex XIII Part B – PMPF plan and PMPF evaluation report requirements
|
||||||
|
|
||||||
|
== Related documents ==
|
||||||
|
|
||||||
|
* [[In Vitro Diagnostic Medical Devices Regulation (EU) 2017/746]] – Parent document
|
||||||
|
* [[MDR 2017/745 – Articles 83–86 & Annex XIV Part B: Post-Market Surveillance and PMCF]] – Equivalent provision for medical devices
|
||||||
|
|
||||||
|
[[Category:In Vitro Diagnostics]]
|
||||||
|
[[Category:Post-Market Surveillance]]
|
||||||
|
[[Category:Clinical]]
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
{{RegDocument
|
||||||
|
| area_of_validity = EU
|
||||||
|
| scope = IVD
|
||||||
|
| document_type = Regulation – Article Reference
|
||||||
|
| name = IVDR (EU) 2017/746 – Article 56 & Annex XIII Part A: Performance Evaluation
|
||||||
|
| version = 2017/746
|
||||||
|
| source = https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R0746#d1e4774-1-1
|
||||||
|
| language = EN, DE, FR
|
||||||
|
| status = Current
|
||||||
|
| restricted_access = No
|
||||||
|
}}
|
||||||
|
|
||||||
|
Article 56 and Annex XIII Part A of the IVDR define the requirements for performance evaluation of IVDs. Performance evaluation is the IVD equivalent of clinical evaluation under the MDR.
|
||||||
|
|
||||||
|
== Summary ==
|
||||||
|
|
||||||
|
Manufacturers must demonstrate that their device achieves its intended performance through a systematic and planned process covering scientific validity, analytical performance, and clinical performance.
|
||||||
|
|
||||||
|
Key obligations:
|
||||||
|
|
||||||
|
* Article 56 – Performance evaluation requirements and documentation
|
||||||
|
* Annex XIII Part A – Performance evaluation plan (PEP) and performance evaluation report (PER)
|
||||||
|
|
||||||
|
The three pillars of performance evaluation:
|
||||||
|
|
||||||
|
* **Scientific validity** – the association between the analyte and a clinical condition or physiological state
|
||||||
|
* **Analytical performance** – the ability to correctly detect or measure a particular analyte (sensitivity, specificity, precision, etc.)
|
||||||
|
* **Clinical performance** – the ability of the device to yield results correlated with a clinical condition in a defined target population
|
||||||
|
|
||||||
|
== Related documents ==
|
||||||
|
|
||||||
|
* [[In Vitro Diagnostic Medical Devices Regulation (EU) 2017/746]] – Parent document
|
||||||
|
|
||||||
|
[[Category:In Vitro Diagnostics]]
|
||||||
|
[[Category:Clinical]]
|
||||||
|
[[Category:Performance Evaluation]]
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
{{RegDocument
|
||||||
|
| area_of_validity = EU
|
||||||
|
| scope = IVD
|
||||||
|
| document_type = Regulation – Article Reference
|
||||||
|
| name = IVDR (EU) 2017/746 – Articles 24–26 & Annex VI: UDI
|
||||||
|
| version = 2017/746
|
||||||
|
| source = https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R0746#d1e3362-1-1
|
||||||
|
| language = EN, DE, FR
|
||||||
|
| status = Current
|
||||||
|
| restricted_access = No
|
||||||
|
}}
|
||||||
|
|
||||||
|
Articles 24 to 26 and Annex VI of the IVDR establish the Unique Device Identification (UDI) system for IVDs placed on the EU market. The framework is aligned with the MDR UDI system.
|
||||||
|
|
||||||
|
== Summary ==
|
||||||
|
|
||||||
|
The UDI system enables unambiguous identification and traceability of IVDs throughout the supply chain and in clinical laboratories.
|
||||||
|
|
||||||
|
Key obligations:
|
||||||
|
|
||||||
|
* Article 24 – UDI assignment and registration in EUDAMED
|
||||||
|
* Article 25 – UDI database (part of EUDAMED)
|
||||||
|
* Article 26 – Registration of devices and economic operators in EUDAMED
|
||||||
|
* Annex VI Part C – Requirements for the UDI carrier (label placement, symbology)
|
||||||
|
|
||||||
|
Application dates by device class:
|
||||||
|
* Class D: May 2022
|
||||||
|
* Class C: May 2023
|
||||||
|
* Class B and A (sterile): May 2025
|
||||||
|
* Class A (non-sterile): May 2027
|
||||||
|
|
||||||
|
== Related documents ==
|
||||||
|
|
||||||
|
* [[In Vitro Diagnostic Medical Devices Regulation (EU) 2017/746]] – Parent document
|
||||||
|
* [[MDR 2017/745 – Articles 27–29 & Annex VI: Unique Device Identification (UDI)]] – Equivalent provision for medical devices
|
||||||
|
|
||||||
|
[[Category:In Vitro Diagnostics]]
|
||||||
|
[[Category:Labelling]]
|
||||||
|
[[Category:Traceability]]
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
{{RegDocument
|
||||||
|
| area_of_validity = EU
|
||||||
|
| scope = MD
|
||||||
|
| document_type = Regulation – Article Reference
|
||||||
|
| name = MDR 2017/745 – Articles 83–86 & Annex XIV Part B: Post-Market Surveillance and PMCF
|
||||||
|
| version = 2017/745
|
||||||
|
| source = https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R0745#d1e6354-1-1
|
||||||
|
| language = EN, DE, FR
|
||||||
|
| status = Current
|
||||||
|
| restricted_access = No
|
||||||
|
}}
|
||||||
|
|
||||||
|
Articles 83 to 86 of the MDR establish the mandatory post-market surveillance (PMS) system for all medical device manufacturers. Annex XIV Part B specifies the requirements for post-market clinical follow-up (PMCF).
|
||||||
|
|
||||||
|
== Summary ==
|
||||||
|
|
||||||
|
Manufacturers must plan, establish, document, implement, maintain, and update a PMS system proportionate to the risk class of the device.
|
||||||
|
|
||||||
|
Key obligations:
|
||||||
|
|
||||||
|
* Article 83 – General PMS requirements and system structure
|
||||||
|
* Article 84 – PMS plan (content requirements)
|
||||||
|
* Article 85 – PMS report (required for Class I devices)
|
||||||
|
* Article 86 – Periodic Safety Update Report (PSUR, required for Class IIa, IIb, III)
|
||||||
|
* Annex XIV Part B – PMCF plan and PMCF evaluation report requirements
|
||||||
|
|
||||||
|
== Related documents ==
|
||||||
|
|
||||||
|
* [[Medical Device Regulation (EU) 2017/745]] – Parent document
|
||||||
|
* [[IVDR (EU) 2017/746 – Articles 78–81 & Annex XIII Part B: Post-Market Performance Follow-Up]] – Equivalent provision for IVDs
|
||||||
|
|
||||||
|
[[Category:Medical Devices]]
|
||||||
|
[[Category:Post-Market Surveillance]]
|
||||||
|
[[Category:Clinical]]
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
{{RegDocument
|
||||||
|
| area_of_validity = EU
|
||||||
|
| scope = MD
|
||||||
|
| document_type = Regulation – Article Reference
|
||||||
|
| name = MDR 2017/745 – Articles 27–29 & Annex VI: Unique Device Identification (UDI)
|
||||||
|
| version = 2017/745
|
||||||
|
| source = https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R0745#d1e3455-1-1
|
||||||
|
| language = EN, DE, FR
|
||||||
|
| status = Current
|
||||||
|
| restricted_access = No
|
||||||
|
}}
|
||||||
|
|
||||||
|
Articles 27 to 29 and Annex VI of the MDR establish the Unique Device Identification (UDI) system for medical devices placed on the EU market.
|
||||||
|
|
||||||
|
== Summary ==
|
||||||
|
|
||||||
|
The UDI system enables unambiguous identification and traceability of devices throughout the supply chain and during clinical use.
|
||||||
|
|
||||||
|
Key obligations:
|
||||||
|
|
||||||
|
* Article 27 – UDI assignment and registration in EUDAMED
|
||||||
|
* Article 28 – UDI database (part of EUDAMED)
|
||||||
|
* Article 29 – Registration of devices and economic operators in EUDAMED
|
||||||
|
* Annex VI Part C – Requirements for the UDI carrier (label placement, symbology)
|
||||||
|
|
||||||
|
Application dates vary by device class:
|
||||||
|
* Class III and implantable: May 2021
|
||||||
|
* Class IIa and IIb: May 2023
|
||||||
|
* Class I: May 2025
|
||||||
|
|
||||||
|
== Related documents ==
|
||||||
|
|
||||||
|
* [[Medical Device Regulation (EU) 2017/745]] – Parent document
|
||||||
|
* [[IVDR (EU) 2017/746 – Articles 24–26 & Annex VI: UDI]] – Equivalent provision for IVDs
|
||||||
|
|
||||||
|
[[Category:Medical Devices]]
|
||||||
|
[[Category:Labelling]]
|
||||||
|
[[Category:Traceability]]
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<includeonly>|-
|
||||||
|
| {{{topic|}}} || {{{category|}}} || {{{scope|}}} || {{{linked_document|}}} || {{{description|}}}
|
||||||
|
</includeonly><noinclude>
|
||||||
|
== Template:Reference ==
|
||||||
|
|
||||||
|
Use this template to add a row to a reference table. Place all <code>{{Reference}}</code> calls between a table header and the closing <code>|}</code>.
|
||||||
|
|
||||||
|
=== Usage ===
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
{| class="wikitable"
|
||||||
|
! Topic / Keyword(s) !! Category / Chapter !! Scope !! Linked document !! Description
|
||||||
|
{{Reference
|
||||||
|
| topic =
|
||||||
|
| category =
|
||||||
|
| scope =
|
||||||
|
| linked_document =
|
||||||
|
| description =
|
||||||
|
}}
|
||||||
|
|}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
=== Fields ===
|
||||||
|
|
||||||
|
{| class="wikitable"
|
||||||
|
! Field !! Description !! Example values
|
||||||
|
|-
|
||||||
|
| <code>topic</code> || Keyword(s) or topic(s), comma-separated || Post-market surveillance, PMCF
|
||||||
|
|-
|
||||||
|
| <code>category</code> || Predefined chapter or database category || Clinical, Labelling, Quality Management
|
||||||
|
|-
|
||||||
|
| <code>scope</code> || Regulatory scope(s), comma-separated || MD, IVD, GMP, PV
|
||||||
|
|-
|
||||||
|
| <code>linked_document</code> || Link to the corresponding RegDocument page || <nowiki>[[MDR 2017/745]]</nowiki>
|
||||||
|
|-
|
||||||
|
| <code>description</code> || Short summary of what this reference covers || Defines requirements for PMCF per Annex XIV Part B.
|
||||||
|
|}
|
||||||
|
|
||||||
|
[[Category:Templates]]
|
||||||
|
</noinclude>
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
{{#set:
|
||||||
|
Area of validity={{{area_of_validity|}}}
|
||||||
|
|Scope={{{scope|}}}
|
||||||
|
|Document type={{{document_type|}}}
|
||||||
|
|Document name={{{name|}}}
|
||||||
|
|Version={{{version|}}}
|
||||||
|
|Source={{{source|}}}
|
||||||
|
|Language={{{language|}}}
|
||||||
|
|Status={{{status|}}}
|
||||||
|
|Restricted access={{{restricted_access|}}}
|
||||||
|
}}<includeonly>{| class="wikitable" style="float:right; clear:right; margin:0 0 1em 1em; width:320px; font-size:0.9em;"
|
||||||
|
! colspan="2" style="background:#f0f4f8; text-align:center;" | Document Information
|
||||||
|
|-
|
||||||
|
! Area of validity
|
||||||
|
| {{{area_of_validity|}}}
|
||||||
|
|-
|
||||||
|
! Scope(s)
|
||||||
|
| {{{scope|}}}
|
||||||
|
|-
|
||||||
|
! Document type
|
||||||
|
| {{{document_type|}}}
|
||||||
|
|-
|
||||||
|
! Document name
|
||||||
|
| {{{name|}}}
|
||||||
|
|-
|
||||||
|
! Version / Revision
|
||||||
|
| {{{version|}}}
|
||||||
|
|-
|
||||||
|
! Official source
|
||||||
|
| {{#if:{{{source|}}}|[{{{source}}} Official link]|—}}
|
||||||
|
|-
|
||||||
|
! Language(s)
|
||||||
|
| {{{language|}}}
|
||||||
|
|-
|
||||||
|
! Status
|
||||||
|
| {{{status|}}}
|
||||||
|
|-
|
||||||
|
! Restricted access
|
||||||
|
| {{{restricted_access|}}}
|
||||||
|
|}</includeonly><noinclude>
|
||||||
|
== Template:RegDocument ==
|
||||||
|
|
||||||
|
Use this template on any page that documents a regulatory document. Place it at the top of the page before any prose content.
|
||||||
|
|
||||||
|
This template also annotates each field as a [[Help:Semantic MediaWiki|Semantic MediaWiki]] property, enabling structured queries across all document pages.
|
||||||
|
|
||||||
|
=== Usage ===
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
{{RegDocument
|
||||||
|
| area_of_validity =
|
||||||
|
| scope =
|
||||||
|
| document_type =
|
||||||
|
| name =
|
||||||
|
| version =
|
||||||
|
| source =
|
||||||
|
| language =
|
||||||
|
| status =
|
||||||
|
| restricted_access =
|
||||||
|
}}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
=== Fields ===
|
||||||
|
|
||||||
|
{| class="wikitable"
|
||||||
|
! Field !! Description !! Example values
|
||||||
|
|-
|
||||||
|
| <code>area_of_validity</code> || Region or country where the document applies || EU, USA, Global, DE
|
||||||
|
|-
|
||||||
|
| <code>scope</code> || Regulatory scope(s), comma-separated || MD, IVD — or NIS, GMP, PV, IMP, GEP, HM
|
||||||
|
|-
|
||||||
|
| <code>document_type</code> || Type of document || Regulation, Directive, Guideline, Scientific article, Treaty
|
||||||
|
|-
|
||||||
|
| <code>name</code> || Full official document name || Medical Device Regulation (EU) 2017/745
|
||||||
|
|-
|
||||||
|
| <code>version</code> || Version, revision or amendment || 2017/745, amended by 2023/607
|
||||||
|
|-
|
||||||
|
| <code>source</code> || URL to the official source || <nowiki>https://eur-lex.europa.eu/...</nowiki>
|
||||||
|
|-
|
||||||
|
| <code>language</code> || Available language(s) || EN, DE, FR
|
||||||
|
|-
|
||||||
|
| <code>status</code> || Validity status || Current, Draft, Final not promulgated, Superseded
|
||||||
|
|-
|
||||||
|
| <code>restricted_access</code> || Blocks copy/paste of content, referencing still allowed || Yes / No
|
||||||
|
|}
|
||||||
|
|
||||||
|
[[Category:Templates]]
|
||||||
|
</noinclude>
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
* Document Database
|
||||||
|
** Document_Index|All documents
|
||||||
|
** Special:Ask|Custom query
|
||||||
|
** Special:Categories|Browse categories
|
||||||
|
|
||||||
|
* navigation
|
||||||
|
** mainpage|mainpage-description
|
||||||
|
** Special:RecentChanges|recentchanges
|
||||||
|
** Special:Random|randompage
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
{{RegDocument
|
||||||
|
| area_of_validity = EU
|
||||||
|
| scope = MD
|
||||||
|
| document_type = Regulation
|
||||||
|
| name = Medical Device Regulation (EU) 2017/745
|
||||||
|
| version = 2017/745, amended by 2023/607
|
||||||
|
| source = https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32017R0745
|
||||||
|
| language = EN, DE, FR (all EU official languages)
|
||||||
|
| status = Current
|
||||||
|
| restricted_access = No
|
||||||
|
}}
|
||||||
|
|
||||||
|
The Medical Device Regulation (MDR) 2017/745 replaces the former Medical Device Directive (MDD 93/42/EEC) and the Active Implantable Medical Device Directive (AIMDD 90/385/EEC). It establishes a uniform regulatory framework for medical devices across EU member states, with a strong focus on clinical evidence, post-market surveillance, and traceability.
|
||||||
|
|
||||||
|
Full application started on 26 May 2021. The amendment 2023/607 introduced a phased transition period for legacy devices.
|
||||||
|
|
||||||
|
== Key references ==
|
||||||
|
|
||||||
|
{| class="wikitable" style="width:100%;"
|
||||||
|
! Topic / Keyword(s) !! Category / Chapter !! Scope !! Linked document !! Description
|
||||||
|
{{Reference
|
||||||
|
| topic = Post-market surveillance, PMCF
|
||||||
|
| category = Clinical
|
||||||
|
| scope = MD
|
||||||
|
| linked_document = [[MDR 2017/745 – Articles 83–86 & Annex XIV Part B: Post-Market Surveillance and PMCF]]
|
||||||
|
| description = Articles 83–86 define the mandatory PMS system; Annex XIV Part B specifies PMCF requirements.
|
||||||
|
}}
|
||||||
|
{{Reference
|
||||||
|
| topic = Unique Device Identification, UDI, Traceability
|
||||||
|
| category = Labelling
|
||||||
|
| scope = MD
|
||||||
|
| linked_document = [[MDR 2017/745 – Articles 27–29 & Annex VI: Unique Device Identification (UDI)]]
|
||||||
|
| description = Articles 27–29 and Annex VI establish the UDI system. All devices must carry a UDI carrier on label and packaging.
|
||||||
|
}}
|
||||||
|
{{Reference
|
||||||
|
| topic = Clinical evaluation, Clinical evidence
|
||||||
|
| category = Clinical
|
||||||
|
| scope = MD
|
||||||
|
| linked_document =
|
||||||
|
| description = Article 61 and Annex XIV Part A define the clinical evaluation process and documentation requirements (CER). ''Page not yet created.''
|
||||||
|
}}
|
||||||
|
|}
|
||||||
|
|
||||||
|
== Related documents ==
|
||||||
|
|
||||||
|
* [[In Vitro Diagnostic Medical Devices Regulation (EU) 2017/746]] – Parallel regulation for IVDs
|
||||||
|
|
||||||
|
[[Category:Medical Devices]]
|
||||||
|
[[Category:EU Regulation]]
|
||||||