WMDE-Fisch has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/316582

Change subject: [WIP] Add SpecialPage frontend code for render method selection
......................................................................

[WIP] Add SpecialPage frontend code for render method selection

Change-Id: Idcb309b392b96932e7fde0ef00ecca1f01d698d5
---
M extension.json
M i18n/en.json
M i18n/qqq.json
A modules/ext.ElectronPdfService.special.css
A modules/ext.ElectronPdfService.special.js
A resources/selection-single-col-ltr.svg
A resources/selection-single-col-rtl.svg
A resources/selection-two-col-ltr.svg
A resources/selection-two-col-rtl.svg
M specials/SpecialElectronPdf.php
10 files changed, 377 insertions(+), 3 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ElectronPdfService 
refs/changes/82/316582/1

diff --git a/extension.json b/extension.json
index 409bdc5..99487cf 100644
--- a/extension.json
+++ b/extension.json
@@ -48,6 +48,36 @@
                        ],
                        "messages": [],
                        "dependencies": []
+               },
+               "ext.ElectronPdfService.special": {
+                       "scripts": [
+                               "modules/ext.ElectronPdfService.special.js"
+                       ],
+                       "styles": [
+                               "modules/ext.ElectronPdfService.special.css"
+                       ],
+                       "dependencies": [
+                               "ext.ElectronPdfService.special.selectionImages"
+                       ]
+               },
+               "ext.ElectronPdfService.special.selectionImages": {
+                       "position": "top",
+                       "class": "ResourceLoaderImageModule",
+                       "selector": ".mw-electronPdfService-selection-{name}",
+                       "images": {
+                               "single-column-image": {
+                                       "file": {
+                                               "ltr": 
"resources/selection-single-col-ltr.svg",
+                                               "rtl": 
"resources/selection-single-col-rtl.svg"
+                                       }
+                               },
+                               "two-column-image": {
+                                       "file": {
+                                               "ltr": 
"resources/selection-two-col-ltr.svg",
+                                               "rtl": 
"resources/selection-two-col-rtl.svg"
+                                       }
+                               }
+                       }
                }
        },
        "ResourceFileModulePaths": {
diff --git a/i18n/en.json b/i18n/en.json
index f3662e3..c878645 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -6,6 +6,13 @@
        },
        "electronPdfService": "ElectronPdfService",
        "electronPdfService-desc": "Adds browser based PDF rendering support 
through Electron PDF service",
+       "electronPdfService-special-page-headline": "Download as PDF",
+       "electronPdfService-select-layout-header": "Select a layout",
+       "electronPdfService-single-column-label": "Single column",
+       "electronPdfService-two-column-label": "Two column",
+       "electronPdfService-single-column-desc": "Includes tables and 
templates",
+       "electronPdfService-two-column-desc": "Without tables and templates",
+       "electronPdfService-download-button": "Download",
        "electronPdfService-sidebar-portlet-heading": "Print",
        "electronPdfService-sidebar-portlet-print-text": "Print PDF",
        "electronPdfService-invalid-page-title": "Invalid page",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 9fa609c..bf47732 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -8,6 +8,13 @@
        },
        "electronPdfService": "electronPdfService",
        "electronPdfService-desc": "{{desc|name=ElectronPdfService|url=}}",
+       "electronPdfService-special-page-headline": "Title for the 
SpecialPage.",
+       "electronPdfService-select-layout-header": "Header for layout 
selection.",
+       "electronPdfService-single-column-label": "Label for the single column 
option.",
+       "electronPdfService-two-column-label": "Label for the two column 
option.",
+       "electronPdfService-single-column-desc": "Short description for the 
single column option.",
+       "electronPdfService-two-column-desc": "Short description for the two 
column option.",
+       "electronPdfService-download-button": "Label for the download button.",
        "electronPdfService-sidebar-portlet-heading": "Title of the portlet in 
which the link is shown.\n{{Identical|Print}}",
        "electronPdfService-sidebar-portlet-print-text": "Text of 
print-pdf-link in sidebar.",
        "electronPdfService-invalid-page-title": "Used as title for the error 
message when specified page was not a valid article.",
diff --git a/modules/ext.ElectronPdfService.special.css 
b/modules/ext.ElectronPdfService.special.css
new file mode 100644
index 0000000..62ae0e3
--- /dev/null
+++ b/modules/ext.ElectronPdfService.special.css
@@ -0,0 +1,65 @@
+.mw-electronPdfService-selection-form {
+    display: block;
+}
+
+.mw-electronPdfService-selection-header {
+    font-weight: bold;
+    margin-bottom: 15px;
+}
+
+.mw-electronPdfService-selection-body {
+    display: table-row;
+}
+
+.mw-electronPdfService-selection-image {
+    background-repeat: no-repeat;
+    width: 100px;
+    height: 100px;
+}
+
+.mw-electronPdfService-selection-form label {
+    display: table-cell;
+    border: 1px solid #c8ccd1;
+    padding: 15px;
+    width: 320px;
+}
+
+.mw-electronPdfService-selection-form  input[type="radio"]:checked ~ b {
+    border: 1px solid blue;
+}
+
+.mw-electronPdfService-selection-form label {
+    display: table-cell;
+    border: 1px solid #c8ccd1;
+    padding: 15px;
+}
+
+.mw-electronPdfService-selection-field, .mw-electronPdfService-selection-image 
{
+    display: table-cell;
+    vertical-align: middle;
+}
+
+.mw-electronPdfService-selection-form .oo-ui-radioInputWidget {
+    margin-bottom: 5px;
+}
+
+/* normally there is no OOUI check icon for the radio box */
+.mw-electronPdfService-selection-form .oo-ui-radioInputWidget 
[type="radio"]:checked + span {
+    /* TODO: find a propper location to get the OOUI icon from */
+    background-image: linear-gradient(transparent, transparent), 
url("https://doc.wikimedia.org/oojs-ui/master/demos/dist/themes/mediawiki/images/icons/check-invert.svg";);
+    background-size: 150%;
+    background-position: center;
+    background-color: #36c;
+    border-color: #36c;
+}
+
+label.mw-electronPdfService-selection-form-selected {
+    background-color: #eaf3ff;
+    border: 1px solid #36c;
+}
+
+.mw-electronPdfService-selection-form .oo-ui-buttonGroupWidget {
+    margin-top: 15px;
+    text-align: right;
+    width: 704px;
+}
diff --git a/modules/ext.ElectronPdfService.special.js 
b/modules/ext.ElectronPdfService.special.js
new file mode 100644
index 0000000..520b313
--- /dev/null
+++ b/modules/ext.ElectronPdfService.special.js
@@ -0,0 +1,13 @@
+( function () {
+       function setSelected( $element ) {
+               $( '.mw-electronPdfService-selection-form label' ).removeClass( 
'mw-electronPdfService-selection-form-selected' );
+               $element.closest( 'label' ).addClass( 
'mw-electronPdfService-selection-form-selected' );
+               $element.blur();
+       }
+
+       setSelected( $( '.mw-electronPdfService-selection-form 
.oo-ui-radioInputWidget :checked' ) );
+
+       $( '.mw-electronPdfService-selection-form .oo-ui-radioInputWidget 
[type="radio"]' ).click( function () {
+               setSelected( $( this ) );
+       } );
+}() );
diff --git a/resources/selection-single-col-ltr.svg 
b/resources/selection-single-col-ltr.svg
new file mode 100644
index 0000000..5cbbab6
--- /dev/null
+++ b/resources/selection-single-col-ltr.svg
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="85" height="101" viewBox="0 0 85 101" 
xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>
+    <title>
+        Group 4
+    </title>
+    <defs>
+        <rect id="path-1" width="79" height="95" rx="2"/>
+        <filter x="-50%" y="-50%" width="200%" height="200%" 
filterUnits="objectBoundingBox" id="filter-2">
+            <feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
+            <feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" 
result="shadowBlurOuter1"/>
+            <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0.213881341 0" in="shadowBlurOuter1"/>
+        </filter>
+    </defs>
+    <g id="Page-1" fill="none" fill-rule="evenodd">
+        <g id="tools-explained-copy-2" transform="translate(-518 -290)">
+            <g id="Group-8" transform="translate(504 276)">
+                <g id="Group-3" transform="translate(17 16)">
+                    <g id="Group-4">
+                        <g id="Rectangle-3">
+                            <use fill="#000" filter="url(#filter-2)" 
xlink:href="#path-1"/>
+                            <use fill="#FFF" xlink:href="#path-1"/>
+                        </g>
+                        <g id="Group-2" opacity=".8" transform="translate(7 
19)" fill="#C8CCD1">
+                            <path id="Rectangle-5-Copy" d="M0 11h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-2" d="M0 17h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-3" d="M0 23h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-16" d="M0 59h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-19" d="M0 65h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-15" opacity=".5" d="M0 
29h65v26H0z"/>
+                            <path id="Rectangle-5" d="M1 0h39v5H1z"/>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/resources/selection-single-col-rtl.svg 
b/resources/selection-single-col-rtl.svg
new file mode 100644
index 0000000..a8a4303
--- /dev/null
+++ b/resources/selection-single-col-rtl.svg
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="85" height="101" viewBox="0 0 
85 101" id="svg2">
+    <title id="title4">
+        Group 4
+    </title>
+    <defs id="defs6">
+        <rect id="path-1" width="79" height="95" rx="2"/>
+        <filter x="-50%" y="-50%" width="200%" height="200%" 
filterUnits="objectBoundingBox" id="filter-2">
+            <feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1" 
id="feOffset10"/>
+            <feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" 
result="shadowBlurOuter1" id="feGaussianBlur12"/>
+            <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0.213881341 0" in="shadowBlurOuter1" id="feColorMatrix14"/>
+        </filter>
+    </defs>
+    <g id="Page-1" transform="matrix(-1 0 0 1 85 0)" fill="none" 
fill-rule="evenodd">
+        <g id="tools-explained-copy-2" transform="translate(-518 -290)">
+            <g id="Group-8" transform="translate(504 276)">
+                <g id="Group-3" transform="translate(17 16)">
+                    <g id="Group-4">
+                        <g id="Rectangle-3">
+                            <use xlink:href="#path-1" id="use22" width="100%" 
height="100%" fill="#000" filter="url(#filter-2)"/>
+                            <use xlink:href="#path-1" id="use24" width="100%" 
height="100%" fill="#fff"/>
+                        </g>
+                        <g id="Group-2" transform="translate(7 19)" 
opacity=".8" fill="#c8ccd1">
+                            <path id="Rectangle-5-Copy" d="M0 11h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-2" d="M0 17h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-3" d="M0 23h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-16" d="M0 59h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-19" d="M0 65h65v2H0z"/>
+                            <path id="Rectangle-5-Copy-15" d="M0 29h65v26H0z" 
opacity=".5"/>
+                            <path id="Rectangle-5" d="M1 0h39v5H1z"/>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/resources/selection-two-col-ltr.svg 
b/resources/selection-two-col-ltr.svg
new file mode 100644
index 0000000..d67711b
--- /dev/null
+++ b/resources/selection-two-col-ltr.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="85" height="101" viewBox="0 0 85 101" 
xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>
+    <title>
+        Group 9
+    </title>
+    <defs>
+        <rect id="path-1" width="79" height="95" rx="2"/>
+        <filter x="-50%" y="-50%" width="200%" height="200%" 
filterUnits="objectBoundingBox" id="filter-2">
+            <feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
+            <feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" 
result="shadowBlurOuter1"/>
+            <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0.213881341 0" in="shadowBlurOuter1"/>
+        </filter>
+    </defs>
+    <g id="Page-1" fill="none" fill-rule="evenodd">
+        <g id="tools-explained-copy-2" transform="translate(-823 -290)">
+            <g id="Group-7" transform="translate(805 276)">
+                <g id="Group-9" transform="translate(21 16)">
+                    <g id="Rectangle-3">
+                        <use fill="#000" filter="url(#filter-2)" 
xlink:href="#path-1"/>
+                        <use fill="#FFF" xlink:href="#path-1"/>
+                    </g>
+                    <g id="Group-2" opacity=".8" transform="translate(9 19)" 
fill="#C8CCD1">
+                        <path id="Rectangle-5" d="M0 0h39v5H0z"/>
+                        <g id="Group-5" transform="translate(1 16)">
+                            <path id="Rectangle-5-Copy" d="M0 0h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-2" d="M0 
7h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-3" d="M0 
14h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-17" d="M0 
21h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-18" d="M0 
28h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-25" d="M0 
35h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-26" d="M0 
42h26.329v2H0z"/>
+                        </g>
+                        <g id="Group-5-Copy" transform="translate(33 16)">
+                            <path id="Rectangle-5-Copy" d="M0 0h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-2" d="M0 
7h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-3" d="M0 
14h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-17" d="M0 
21h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-18" d="M0 
28h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-25" d="M0 
35h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-26" d="M0 
42h26.329v2H0z"/>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/resources/selection-two-col-rtl.svg 
b/resources/selection-two-col-rtl.svg
new file mode 100644
index 0000000..fde68ac
--- /dev/null
+++ b/resources/selection-two-col-rtl.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; width="85" height="101" viewBox="0 0 
85 101" id="svg2">
+    <title id="title4">
+        Group 9
+    </title>
+    <defs id="defs6">
+        <rect id="path-1" width="79" height="95" rx="2"/>
+        <filter x="-50%" y="-50%" width="200%" height="200%" 
filterUnits="objectBoundingBox" id="filter-2">
+            <feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1" 
id="feOffset10"/>
+            <feGaussianBlur stdDeviation="1.5" in="shadowOffsetOuter1" 
result="shadowBlurOuter1" id="feGaussianBlur12"/>
+            <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0.213881341 0" in="shadowBlurOuter1" id="feColorMatrix14"/>
+        </filter>
+    </defs>
+    <g id="Page-1" transform="matrix(-1 0 0 1 85 0)" fill="none" 
fill-rule="evenodd">
+        <g id="tools-explained-copy-2" transform="translate(-823 -290)">
+            <g id="Group-7" transform="translate(805 276)">
+                <g id="Group-9" transform="translate(21 16)">
+                    <g id="Rectangle-3">
+                        <use xlink:href="#path-1" id="use21" width="100%" 
height="100%" fill="#000" filter="url(#filter-2)"/>
+                        <use xlink:href="#path-1" id="use23" width="100%" 
height="100%" fill="#fff"/>
+                    </g>
+                    <g id="Group-2" transform="translate(9 19)" opacity=".8" 
fill="#c8ccd1">
+                        <path id="Rectangle-5" d="M0 0h39v5H0z"/>
+                        <g id="Group-5" transform="translate(1 16)">
+                            <path id="Rectangle-5-Copy" d="M0 0h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-2" d="M0 
7h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-3" d="M0 
14h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-17" d="M0 
21h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-18" d="M0 
28h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-25" d="M0 
35h26.329v2H0z"/>
+                            <path id="Rectangle-5-Copy-26" d="M0 
42h26.329v2H0z"/>
+                        </g>
+                        <g id="Group-5-Copy" transform="translate(33 16)">
+                            <path id="path36" d="M0 0h26.329v2H0z"/>
+                            <path id="path38" d="M0 7h26.329v2H0z"/>
+                            <path id="path40" d="M0 14h26.329v2H0z"/>
+                            <path id="path42" d="M0 21h26.329v2H0z"/>
+                            <path id="path44" d="M0 28h26.329v2H0z"/>
+                            <path id="path46" d="M0 35h26.329v2H0z"/>
+                            <path id="path48" d="M0 42h26.329v2H0z"/>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
diff --git a/specials/SpecialElectronPdf.php b/specials/SpecialElectronPdf.php
index 942bf25..4e136b0 100644
--- a/specials/SpecialElectronPdf.php
+++ b/specials/SpecialElectronPdf.php
@@ -27,10 +27,7 @@
                $request = $this->getRequest();
                $parts = ( $subPage === '' ) ? [] : explode( '/', $subPage, 2 );
                $page = trim( $request->getVal( 'page', isset( $parts[0] ) ? 
$parts[0] : '' ) );
-               $this->renderAndShowPdf( $page );
-       }
 
-       public function renderAndShowPdf( $page ) {
                $title = Title::newFromText( $page );
                if ( $title === null ) {
                        $this->getOutput()->showErrorPage(
@@ -40,6 +37,78 @@
                        return;
                }
 
+//             TODO: build a propper switch here and consider input if a 
method was selected
+
+               $this->showRenderModeSelectionPage( $title );
+//             $this->renderAndShowPdf( $title, $page );
+       }
+
+       public function showRenderModeSelectionPage( Title $title ) {
+               $this->setHeaders();
+
+               $out = $this->getOutput();
+               $out->enableOOUI();
+               $out->setPageTitle( $this->msg( 
'electronPdfService-special-page-headline' )->text() );
+               $out->addSubtitle( $title->getText() );
+
+               $form = new OOUI\FormLayout( array(
+                       'method' => 'POST',
+                       'action' => '',
+               ) );
+
+               $form->addClasses( [ 'mw-electronPdfService-selection-form' ] );
+
+               $form->appendContent(
+                       ( new OOUI\Tag() )
+                               ->addClasses( [ 
'mw-electronPdfService-selection-header' ] )
+                               ->appendContent( $this->msg( 
'electronPdfService-select-layout-header' )->text() ),
+                       ( new OOUI\Tag() )
+                               ->addClasses( [ 
'mw-electronPdfService-selection-body' ] )
+                               ->appendContent(
+                                       $this->getLabeledOptionField( 'single' 
),
+                                       $this->getLabeledOptionField( 'two' )
+                               )
+               );
+
+               $form->appendContent( new OOUI\ButtonGroupWidget( [
+                       'items' => [
+                               new OOUI\ButtonInputWidget( [
+                                       'type' => 'submit',
+                                       'name' => 'continue',
+                                       'value' => 'go',
+                                       'flags' => [ 'primary', 'progressive' ],
+                                       'label' => $this->msg( 
'electronPdfService-download-button' )->text(),
+                               ] ),
+                       ],
+               ] ) );
+
+               $out->addHTML( $form );
+       }
+
+       public function getLabeledOptionField( $name ) {
+               $image = ( new OOUI\Tag() )->addClasses( [
+                       'mw-electronPdfService-selection-image',
+                       'mw-electronPdfService-selection-' . $name . 
'-column-image'
+               ] );
+
+               $field = ( new OOUI\Tag() )->addClasses( [ 
'mw-electronPdfService-selection-field' ] );
+               $field->appendContent(
+                       new OOUI\RadioInputWidget( [
+                               'name' => 'column-type',
+                               'value' => $name,
+                       ] ),
+                       ( new OOUI\Tag( 'b' ) )->appendContent( $this->msg( 
'electronPdfService-' . $name . '-column-label' )->text() ),
+                       ( new OOUI\Tag() )->appendContent( $this->msg( 
'electronPdfService-' . $name . '-column-desc' )->text() )
+               );
+
+               $labelBox = ( new OOUI\Tag( 'label' ) )->appendContent(
+                       $image,
+                       $field
+               );
+               return $labelBox;
+       }
+
+       public function renderAndShowPdf( Title $title, $page ) {
                $this->tempFile = tmpfile();
 
                $request = MWHttpRequest::factory( $this->constructServiceUrl( 
$title ) );
@@ -61,6 +130,21 @@
                return fwrite( $this->tempFile, $content );
        }
 
+       public function setHeaders() {
+               parent::setHeaders();
+               $this->addModules();
+       }
+
+       protected function addModules() {
+               $out = $this->getOutput();
+               $rl = $out->getResourceLoader();
+               $specialModuleName = 'ext.ElectronPdfService.special';
+
+               if ( $rl->isModuleRegistered( $specialModuleName ) ) {
+                       $out->addModules( $specialModuleName );
+               }
+       }
+
        private function constructServiceUrl( Title $title ) {
                $electronPdfService = $this->config->get( 'ElectronPdfService' 
);
 

-- 
To view, visit https://gerrit.wikimedia.org/r/316582
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Idcb309b392b96932e7fde0ef00ecca1f01d698d5
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/ElectronPdfService
Gerrit-Branch: master
Gerrit-Owner: WMDE-Fisch <christoph.jau...@wikimedia.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to