Jdlrobson has uploaded a new change for review.
https://gerrit.wikimedia.org/r/111394
Change subject: Special:MobileWebApp and Special:Manifests
......................................................................
Special:MobileWebApp and Special:Manifests
Introduce a new special page with AppCached HTML
(CSS and JavaScript is not appcached... yet)
* Update JavaScript modules to support an app mode
Change-Id: Ifc9c405766f5a95d1a97d36808ecf5992901a80b
---
M MobileFrontend.alias.php
M MobileFrontend.i18n.php
M MobileFrontend.php
M includes/MobileFrontend.hooks.php
M includes/Resources.php
M includes/skins/MinervaTemplate.php
M includes/skins/SkinMinerva.php
A includes/skins/SkinMinervaApp.php
A includes/specials/SpecialManifests.php
A includes/specials/SpecialMobileWebApp.php
A javascripts/app/startup.js
M javascripts/common/OverlayNew.js
M javascripts/common/history-alpha.js
M javascripts/common/modules.js
M javascripts/loggingSchemas/MobileWebClickTracking.js
M javascripts/modules/lastEdited/lastEditedBeta.js
M javascripts/modules/lazyload.js
M javascripts/modules/mediaViewer.js
M javascripts/modules/search/search.js
M javascripts/modules/talk/talk.js
A less/app/common.less
M less/common/uiNew.less
M less/modules/issues.less
23 files changed, 224 insertions(+), 30 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend
refs/changes/94/111394/1
diff --git a/MobileFrontend.alias.php b/MobileFrontend.alias.php
index c05a009..22c5489 100644
--- a/MobileFrontend.alias.php
+++ b/MobileFrontend.alias.php
@@ -12,6 +12,8 @@
/** English (English) */
$specialPageAliases['en'] = array(
'History' => array( 'History' ),
+ 'MobileWebApp' => array( 'MobileWebApp' ),
+ 'Manifests' => array( 'Manifests' ),
'MobileOptions' => array( 'MobileOptions' ),
'Uploads' => array( 'Uploads' ),
'MobileDiff' => array( 'MobileDiff' ),
@@ -253,4 +255,4 @@
'MobileDiff' => array( '手機版差異' ),
'MobileMenu' => array( '手機版選單' ),
'Nearby' => array( '附近' ),
-);
\ No newline at end of file
+);
diff --git a/MobileFrontend.i18n.php b/MobileFrontend.i18n.php
index 70f38bf..3ec44fd 100644
--- a/MobileFrontend.i18n.php
+++ b/MobileFrontend.i18n.php
@@ -391,6 +391,8 @@
// Preferences for toggling mobile skins
'beta-feature-minerva' => 'Enable mobile skin (Minerva) on desktop',
'beta-feature-minerva-description' => 'Make the skin used on mobile
devices a selectable desktop skin under the appearance preferences tab.',
+ // App
+ 'mobile-frontend-app-title' => 'Mobile App',
);
/** Message documentation (Message documentation)
@@ -1094,6 +1096,7 @@
'beta-feature-minerva-description' => 'Describe the Minerva beta
feature - it makes a new skin available.
This description is for the label {{msg-mw|Beta-feature-minerva}}.',
+ 'mobile-frontend-app-title' => 'Page title for the mobile web
standalone app at Special:MobileWebApp',
);
/** Achinese (Acèh)
diff --git a/MobileFrontend.php b/MobileFrontend.php
index f677a8d..612e31c 100644
--- a/MobileFrontend.php
+++ b/MobileFrontend.php
@@ -64,6 +64,8 @@
'MFResourceLoaderModule' => 'modules/MFResourceLoaderModule',
'MobileSiteModule' => 'modules/MobileSiteModule',
+ 'SpecialMobileWebApp' => 'specials/SpecialMobileWebApp',
+ 'SpecialManifests' => 'specials/SpecialManifests',
'SpecialUploads' => 'specials/SpecialUploads',
'SpecialUserProfile' => 'specials/SpecialUserProfile',
'SpecialMobileHistory' => 'specials/SpecialMobileHistory',
@@ -89,6 +91,7 @@
'SkinMinerva' => 'skins/SkinMinerva',
'SkinMinervaBeta' => 'skins/SkinMinervaBeta',
'SkinMinervaAlpha' => 'skins/SkinMinervaAlpha',
+ 'SkinMinervaApp' => 'skins/SkinMinervaApp',
'SkinMobileWML' => 'skins/SkinMobileWML',
'UserLoginAndCreateTemplate' => 'skins/UserLoginAndCreateTemplate',
'UserLoginMobileTemplate' => 'skins/UserLoginMobileTemplate',
@@ -137,6 +140,8 @@
$wgHooks['ResourceLoaderRegisterModules'][] =
'MobileFrontendHooks::onResourceLoaderRegisterModules';
$wgHooks['OutputPageParserOutput'][] =
'MobileFrontendHooks::onOutputPageParserOutput';
+$wgSpecialPages['MobileWebApp'] = 'SpecialMobileWebApp';
+$wgSpecialPages['Manifests'] = 'SpecialManifests';
$wgSpecialPages['MobileDiff'] = 'SpecialMobileDiff';
$wgSpecialPages['MobileEditor'] = 'SpecialMobileEditor';
$wgSpecialPages['MobileOptions'] = 'SpecialMobileOptions';
diff --git a/includes/MobileFrontend.hooks.php
b/includes/MobileFrontend.hooks.php
index b6250a9..ba2b0dd 100644
--- a/includes/MobileFrontend.hooks.php
+++ b/includes/MobileFrontend.hooks.php
@@ -91,10 +91,18 @@
$skinName = $wgMFDefaultSkinClass;
$betaSkinName = $skinName . 'Beta';
$alphaSkinName = $skinName . 'Alpha';
+ $appSkinName = $skinName . 'App';
+
// Force alpha for test mode to sure all modules can run
+ $key = $mobileContext->getTitle()->getDBkey();
$inTestMode =
- $context->getTitle()->getDBkey() ===
SpecialPage::getTitleFor( 'JavaScriptTest', 'qunit' )->getDBkey();
- if ( ( $mobileContext->isAlphaGroupMember() ||
$inTestMode ) && class_exists( $alphaSkinName ) ) {
+ $key === SpecialPage::getTitleFor(
'JavaScriptTest', 'qunit' )->getDBkey();
+
+ list( $name, /* $subpage */ ) =
SpecialPageFactory::resolveAlias( $key );
+ if ( $name && $name === 'MobileWebApp' ) {
+ $skinName = $appSkinName;
+ } else if ( ( $mobileContext->isAlphaGroupMember() ||
$inTestMode ) && class_exists( $alphaSkinName ) ) {
+
$skinName = $alphaSkinName;
} else if ( $mobileContext->isBetaGroupMember() &&
class_exists( $betaSkinName ) ) {
$skinName = $betaSkinName;
diff --git a/includes/Resources.php b/includes/Resources.php
index 7b47baa..e70af3b 100644
--- a/includes/Resources.php
+++ b/includes/Resources.php
@@ -508,6 +508,8 @@
'mobile.search' => $wgMFMobileResourceBoilerplate + array(
'dependencies' => array(
+ // Make sure we have articleList template
+ 'mobile.stable.common',
'mobile.overlays'
),
'styles' => array(
@@ -602,6 +604,20 @@
'scripts' => array(
'javascripts/modules/mf-translator.js',
'javascripts/modules/random/random.js',
+ ),
+ ),
+
+ 'mobile.app' => $wgMFMobileResourceBoilerplate + array(
+ 'dependencies' => array(
+ 'mobile.ajaxpages',
+ 'mobile.startup',
+ 'mobile.search',
+ ),
+ 'scripts' => array(
+ 'javascripts/app/startup.js',
+ ),
+ 'styles' => array(
+ 'less/app/common.less',
),
),
@@ -994,7 +1010,6 @@
'mobile.nearby' => $wgMFMobileResourceBoilerplate + array(
'templates' => array(
- 'articleList',
'overlays/pagePreview',
),
'dependencies' => array(
diff --git a/includes/skins/MinervaTemplate.php
b/includes/skins/MinervaTemplate.php
index 8c3830b..4a9991f 100644
--- a/includes/skins/MinervaTemplate.php
+++ b/includes/skins/MinervaTemplate.php
@@ -179,7 +179,7 @@
protected function renderContentWrapper( $data ) {
?>
<script>
- mw.mobileFrontend.emit( 'header-loaded' );
+ if ( window.mw && mw.mobileFrontend ) {
mw.mobileFrontend.emit( 'header-loaded' ); }
</script>
<?php
$this->renderPreContent( $data );
diff --git a/includes/skins/SkinMinerva.php b/includes/skins/SkinMinerva.php
index 3ca12a7..b55fad0 100644
--- a/includes/skins/SkinMinerva.php
+++ b/includes/skins/SkinMinerva.php
@@ -119,14 +119,14 @@
} else if ( $title->isSpecialPage() ) {
$className .= ' mw-mf-special ';
}
- if ( !$this->getUser()->isAnon() ) {
+ if ( $this->isAuthenticatedUser() ) {
$className .= ' is-authenticated';
}
return $className;
}
/**
- * @return string: The current mode of the skin [stable|beta|alpha]
that is running
+ * @return string: The current mode of the skin [stable|beta|alpha|app]
that is running
*/
protected function getMode() {
return $this->mode;
@@ -136,6 +136,14 @@
* @var MobileContext
*/
protected $mobileContext;
+
+ /**
+ * FIXME: This helper function is only truly needed whilst
SkinMobileApp does not support login
+ * @return Boolean: Whether the current user is authenticated or not.
+ */
+ protected function isAuthenticatedUser() {
+ return !$this->getUser()->isAnon();
+ }
public function __construct() {
$this->mobileContext = MobileContext::singleton();
@@ -620,7 +628,7 @@
'wgMFIsUserBlocked' => $user->isBlocked(),
), $this->getSkinConfigMobileVariables() );
- if ( !$user->isAnon() ) {
+ if ( $this->isAuthenticatedUser() ) {
$vars['wgWatchedPageCache'] = array(
$title->getPrefixedDBkey() => $user->isWatched(
$title ),
);
diff --git a/includes/skins/SkinMinervaApp.php
b/includes/skins/SkinMinervaApp.php
new file mode 100644
index 0000000..2f23c69
--- /dev/null
+++ b/includes/skins/SkinMinervaApp.php
@@ -0,0 +1,31 @@
+<?php
+class SkinMinervaApp extends SkinMinervaBeta {
+ protected $mode = 'app';
+
+ public function getHtmlElementAttributes() {
+ global $wgScriptPath, $wgScriptExtension;
+
+ $attrs = parent::getHtmlElementAttributes();
+ $skin = $this->skinname;
+ $out = $this->getOutput();
+ $target = $out->getTarget();
+ $lang = $this->getLanguage()->getCode();
+ $queryString = "?skin={$skin}&target={$target}&lang={$lang}";
+ $attrs['manifest'] = Title::makeTitle( NS_SPECIAL, 'Manifests'
)->getLocalURL() . $queryString;
+ return $attrs;
+ }
+
+ // FIXME: Get login to work in JavaScript
+ protected function isAuthenticatedUser() {
+ return false;
+ }
+
+ protected function prepareUserButton( BaseTemplate $tpl ) {
+ $tpl->set( 'secondaryButton', '' );
+ }
+
+ public function getDefaultModules() {
+ return array();
+ }
+}
+
diff --git a/includes/specials/SpecialManifests.php
b/includes/specials/SpecialManifests.php
new file mode 100644
index 0000000..9f58cf6
--- /dev/null
+++ b/includes/specials/SpecialManifests.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * This generates webapp manifests and AppCache manifests.
+ * This sort of technology is used in Firefox OS and the Chrome Web Store.
+ */
+
+class SpecialManifests extends UnlistedSpecialPage {
+
+ private static $invalid = "invalid manifest params";
+ private static $me; // url of this script - Special:SpecialManifests
+ private static $mwa; // relative Special:MobileWebApp
+
+ public function __construct() {
+ parent::__construct( 'Manifests' );
+ self::$me = Title::makeTitle( NS_SPECIAL, 'Manifests' );
+ self::$mwa = Title::makeTitle( NS_SPECIAL, 'MobileWebApp' );
+ }
+
+ public function execute( $par ) {
+ $out = $this->getOutput();
+ $out->disable();
+
+ $request = $this->getRequest();
+ $response = $request->response();
+ $this->genAppCache( $request, $response );
+ }
+
+ private function genAppCache( WebRequest $req, WebResponse $resp ) {
+ $resourceLoaderMF = new MFResourceLoaderModule( array() );
+ $rlDummyCtx = ResourceLoaderContext::newDummyContext();
+ $mfTimestamp = $resourceLoaderMF->getModifiedTime( $rlDummyCtx
);
+ $mfWfTs = wfTimestamp( TS_ISO_8601_BASIC, $mfTimestamp );
+
+ $urls = "# $mfTimestamp - $mfWfTs\n";
+ $checksum = sha1( $urls );
+
+ $resp->header( 'Content-type: text/cache-manifest;
charset=UTF-8' );
+ $resp->header( 'Cache-Control: public, max-age=300,
s-max-age=300' );
+ $resp->header( "ETag: $checksum" );
+
+ echo <<<HTML
+CACHE MANIFEST
+
+NETWORK:
+*
+
+HTML;
+
+ echo <<<HTML
+
+CACHE:
+{$urls}
+
+# {$checksum}
+
+HTML;
+ }
+}
diff --git a/includes/specials/SpecialMobileWebApp.php
b/includes/specials/SpecialMobileWebApp.php
new file mode 100644
index 0000000..afab427
--- /dev/null
+++ b/includes/specials/SpecialMobileWebApp.php
@@ -0,0 +1,13 @@
+<?php
+
+class SpecialMobileWebApp extends MobileSpecialPage {
+ protected $disableSearchAndFooter = false;
+ public function __construct() {
+ parent::__construct( 'MobileWebApp' );
+ }
+ public function executeWhenAvailable( $par ) {
+ $out = $this->getOutput();
+ $out->addModules( 'mobile.app' );
+ $out->setPageTitle( $this->msg( 'mobile-frontend-app-title'
)->escaped() );
+ }
+}
diff --git a/javascripts/app/startup.js b/javascripts/app/startup.js
new file mode 100644
index 0000000..3160297
--- /dev/null
+++ b/javascripts/app/startup.js
@@ -0,0 +1,23 @@
+( function( M, $ ) {
+ var mainPage = mw.config.get( 'wgMainPageTitle' );
+
+ $( function() {
+ if ( M.history.navigateToPage ) {
+ // Drastically simplify the left menu
+ // FIXME: Make all buttons work via JavaScript
+ $( '#mw-mf-page-left' ).find( 'li:not(.icon-home)'
).remove();
+
+ // make main link open in main page.
+ $( '#mw-mf-page-left .icon-home a' ).on( M.tapEvent(
'click' ), function( ev ) {
+ ev.preventDefault();
+ M.history.navigateToPage( mainPage );
+ } );
+
+ // lazy load main page
+ M.history.navigateToPage( mainPage );
+ } else {
+ // FIXME: Show app unavailable error
+ }
+ } );
+
+}( mw.mobileFrontend, jQuery ) );
diff --git a/javascripts/common/OverlayNew.js b/javascripts/common/OverlayNew.js
index 07d72da..c15a985 100644
--- a/javascripts/common/OverlayNew.js
+++ b/javascripts/common/OverlayNew.js
@@ -1,6 +1,5 @@
// FIXME: merge with Overlay and remove when OverlayNew gets to stable
( function( M ) {
-
var Overlay = M.require( 'Overlay' ), OverlayNew;
/**
* @name OverlayNew
diff --git a/javascripts/common/history-alpha.js
b/javascripts/common/history-alpha.js
index ef82822..f67cb57 100644
--- a/javascripts/common/history-alpha.js
+++ b/javascripts/common/history-alpha.js
@@ -1,5 +1,5 @@
( function( M, $ ) {
- M.assertMode( [ 'alpha' ] );
+ M.assertMode( [ 'alpha', 'app' ] );
var
Page = M.require( 'Page' ),
@@ -22,6 +22,12 @@
return args[0] + '?' + $.param( params );
}
+ function renderPage( title ) {
+ new Page( { title: title, el: $( '#content_wrapper' ) } ).on(
'error', function() {
+ window.location.reload(); // the page either doesn't
exist or was a Special:Page so force a refresh
+ } ).on( 'ready', M.reloadPage );
+ }
+
// do not run more than once
function init() {
// use wgPageName to ensure we keep the namespace prefix
@@ -38,9 +44,7 @@
// The main page has various special cases so
force a reload
window.location = mw.util.getUrl( title );
} else if ( currentUrl !== s.url ) {
- new Page( { title: title, el: $(
'#content_wrapper' ) } ).on( 'error', function() {
- window.location.reload(); // the page
either doesn't exist or was a Special:Page so force a refresh
- } ).on( 'ready', M.reloadPage );
+ renderPage( s.title );
}
currentUrl = s.url;
} );
@@ -53,7 +57,11 @@
* a new one.
*/
function navigateToPage( title, replaceState ) {
- History[replaceState ? 'replaceState' : 'pushState'](
null, title, mw.util.getUrl( title ) );
+ if ( M.isApp() ) {
+ renderPage( title );
+ } else {
+ History[replaceState ? 'replaceState' :
'pushState']( null, title, mw.util.getUrl( title ) );
+ }
}
/**
@@ -98,6 +106,7 @@
}
return {
+ navigateToPage: navigateToPage,
hijackLinks: hijackLinks
};
}
@@ -107,7 +116,7 @@
updateQueryStringParameter: updateQueryStringParameter
};
- if ( History.enabled && !M.inNamespace( 'special' ) ) {
+ if ( History.enabled && ( !M.inNamespace( 'special' ) || M.isApp() ) ) {
$.extend( M.history, init() );
}
diff --git a/javascripts/common/modules.js b/javascripts/common/modules.js
index 8198949..657adcd 100644
--- a/javascripts/common/modules.js
+++ b/javascripts/common/modules.js
@@ -20,6 +20,15 @@
},
/**
+ * @name M.isApp
+ * @function
+ * @return {Boolean}
+ */
+ isApp: function() {
+ return mw.config.get( 'wgMFMode' ) === 'app';
+ },
+
+ /**
* @name M.assertMode
* @function
* @throws Error when a module is run out of its allowed modes
diff --git a/javascripts/loggingSchemas/MobileWebClickTracking.js
b/javascripts/loggingSchemas/MobileWebClickTracking.js
index 1e38007..2d350f5 100644
--- a/javascripts/loggingSchemas/MobileWebClickTracking.js
+++ b/javascripts/loggingSchemas/MobileWebClickTracking.js
@@ -35,13 +35,15 @@
} );
// Add EventLogging to hamburger menu
- hijackLink( '#mw-mf-page-left .icon-home a', 'hamburger-home' );
- hijackLink( '#mw-mf-page-left .icon-random a', 'hamburger-random' );
- hijackLink( '#mw-mf-page-left .icon-nearby a', 'hamburger-nearby' );
- hijackLink( '#mw-mf-page-left .icon-watchlist a', 'hamburger-watchlist'
);
- hijackLink( '#mw-mf-page-left .icon-settings a', 'hamburger-settings' );
- hijackLink( '#mw-mf-page-left .icon-uploads a', 'hamburger-uploads' );
- hijackLink( '#mw-mf-page-left .icon-profile', 'hamburger-profile' );
- hijackLink( '#mw-mf-page-left .icon-anon a', 'hamburger-login' );
- hijackLink( '#mw-mf-page-left .icon-secondary-logout',
'hamburger-logout' );
+ if ( !M.isApp() ) {
+ hijackLink( '#mw-mf-page-left .icon-home a', 'hamburger-home' );
+ hijackLink( '#mw-mf-page-left .icon-random a',
'hamburger-random' );
+ hijackLink( '#mw-mf-page-left .icon-nearby a',
'hamburger-nearby' );
+ hijackLink( '#mw-mf-page-left .icon-watchlist a',
'hamburger-watchlist' );
+ hijackLink( '#mw-mf-page-left .icon-settings a',
'hamburger-settings' );
+ hijackLink( '#mw-mf-page-left .icon-uploads a',
'hamburger-uploads' );
+ hijackLink( '#mw-mf-page-left .icon-profile',
'hamburger-profile' );
+ hijackLink( '#mw-mf-page-left .icon-anon a', 'hamburger-login'
);
+ hijackLink( '#mw-mf-page-left .icon-secondary-logout',
'hamburger-logout' );
+ }
} )( mw.mobileFrontend, jQuery );
diff --git a/javascripts/modules/lastEdited/lastEditedBeta.js
b/javascripts/modules/lastEdited/lastEditedBeta.js
index 16b6c47..4ac99cb 100644
--- a/javascripts/modules/lastEdited/lastEditedBeta.js
+++ b/javascripts/modules/lastEdited/lastEditedBeta.js
@@ -1,6 +1,6 @@
( function( M, $ ) {
-M.assertMode( [ 'beta', 'alpha' ] );
+M.assertMode( [ 'beta', 'alpha', 'app' ] );
( function() {
var time = M.require( 'modules/lastEdited/time' );
diff --git a/javascripts/modules/lazyload.js b/javascripts/modules/lazyload.js
index a6507dc..da37261 100644
--- a/javascripts/modules/lazyload.js
+++ b/javascripts/modules/lazyload.js
@@ -1,8 +1,9 @@
( function( M, $ ) {
+ M.assertMode( [ 'alpha', 'app' ] );
var history = M.history,
// FIXME: use fuzzy link hijacking in the main namespace - core
should be updated to make links more explicit
- useFuzzyLinkHijacking = M.inNamespace( '' );
+ useFuzzyLinkHijacking = M.inNamespace( '' ) || M.isApp();
if ( history.hijackLinks ) {
history.hijackLinks( $( '#content' ), useFuzzyLinkHijacking );
diff --git a/javascripts/modules/mediaViewer.js
b/javascripts/modules/mediaViewer.js
index c2e6977..2370067 100644
--- a/javascripts/modules/mediaViewer.js
+++ b/javascripts/modules/mediaViewer.js
@@ -1,5 +1,5 @@
( function( M, $ ) {
- M.assertMode( [ 'alpha', 'beta' ] );
+ M.assertMode( [ 'alpha', 'beta', 'app' ] );
var Overlay = M.require( 'Overlay' ),
Api = M.require( 'api' ).Api,
diff --git a/javascripts/modules/search/search.js
b/javascripts/modules/search/search.js
index eee47cf..347b00b 100644
--- a/javascripts/modules/search/search.js
+++ b/javascripts/modules/search/search.js
@@ -21,7 +21,7 @@
// FIXME: ugly hack that removes search from browser history when
navigating
// to search results (we can't rely on History API yet)
// alpha does it differently in lazyload.js
- if ( !M.isAlphaGroupMember() ) {
+ if ( !M.isAlphaGroupMember() && !M.isApp() ) {
M.on( 'search-results', function( overlay ) {
overlay.$( '.results a' ).on( 'click', function( ev ) {
var href = $( this ).attr( 'href' );
diff --git a/javascripts/modules/talk/talk.js b/javascripts/modules/talk/talk.js
index 64252c9..2c451cf 100644
--- a/javascripts/modules/talk/talk.js
+++ b/javascripts/modules/talk/talk.js
@@ -1,7 +1,7 @@
( function( M, $ ) {
var LoadingOverlay = M.require( 'LoadingOverlayNew' );
- M.assertMode( [ 'beta', 'alpha' ] );
+ M.assertMode( [ 'beta', 'alpha', 'app' ] );
function onTalkClick( ev ) {
var talkPage = $( this ).data( 'title' ),
diff --git a/less/app/common.less b/less/app/common.less
new file mode 100644
index 0000000..a0f3a93
--- /dev/null
+++ b/less/app/common.less
@@ -0,0 +1,6 @@
+// FIXME: In future we want to support all of these!
+.edit-page,
+#mw-mf-language-section,
+#page-actions {
+ display: none !important;
+}
diff --git a/less/common/uiNew.less b/less/common/uiNew.less
index 2adcc36..2fc2441 100644
--- a/less/common/uiNew.less
+++ b/less/common/uiNew.less
@@ -2,7 +2,7 @@
@import "minerva.mixins";
@import "minerva.variables";
-.beta, .alpha {
+.app, .beta, .alpha {
.top-bar {
background-color: #F3F3F3;
padding: 5px @contentMargin;
diff --git a/less/modules/issues.less b/less/modules/issues.less
index 16c1057..7fb7653 100644
--- a/less/modules/issues.less
+++ b/less/modules/issues.less
@@ -27,6 +27,7 @@
}
}
+.app,
.alpha,
.beta {
.mw-mf-cleanup {
--
To view, visit https://gerrit.wikimedia.org/r/111394
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifc9c405766f5a95d1a97d36808ecf5992901a80b
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Jdlrobson <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits