jenkins-bot has submitted this change and it was merged.
Change subject: Hide charge-inducing features. Intercept link interstitials
sooner.
......................................................................
Hide charge-inducing features. Intercept link interstitials sooner.
* HTTPS can cause charges. This hides obvious HTTPS chrome until safe.
* Rewritten hyperlinks normally result in a server roundtrip upon click.
* This patch tries to render a client-side interstitial opportunistically.
* However, without binding to all click events, some clicks will default to the
server.
* For hyperlinks that look like Wikipedia language switches, a last-ditch
server check is allowed.
* Eventually, HTTPS will be supported via IP zero-rating. At that point, this
code should be updated.
Change-Id: Icd8c9140e3a22de60e148670f7bbc67a356950d8
---
M ZeroRatedMobileAccess.php
M includes/ApiZeroConfig.php
A modules/ZeroOverlay.js
A modules/carrierConfig.js
A modules/interstitial.js
A modules/redux.js
A modules/redux.less
A templates/interstitial.html
8 files changed, 199 insertions(+), 3 deletions(-)
Approvals:
JGonera: Looks good to me, but someone else must approve
Yurik: Looks good to me, approved
jenkins-bot: Verified
diff --git a/ZeroRatedMobileAccess.php b/ZeroRatedMobileAccess.php
index 32329d5..1bd428f 100644
--- a/ZeroRatedMobileAccess.php
+++ b/ZeroRatedMobileAccess.php
@@ -60,15 +60,27 @@
'localBasePath' => $localBasePath,
'remoteExtPath' => $remoteExtPath,
'targets' => array( 'mobile' ),
- 'styles' => array( 'modules/banner.css' ),
+ 'styles' => array( 'modules/banner.css', 'modules/redux.less' ),
+);
+
+$wgResourceModules['mobile.zero.templates'] = array(
+ 'localBasePath' => $localBasePath,
+ 'localTemplateBasePath' => $localBasePath . '/templates',
+ 'templates' => array( 'interstitial' ),
+ 'class' => 'MFResourceLoaderModule',
);
$wgResourceModules['mobile.zero.scripts'] = array(
- 'dependencies' => array( 'mobile.startup' ),
+ 'dependencies' => array( 'mobile.stable', 'mobile.zero.styles',
'mobile.zero.templates' ),
'localBasePath' => $localBasePath,
'remoteExtPath' => $remoteExtPath,
'targets' => array( 'mobile' ),
- 'scripts' => array( 'modules/banner.js' ),
+ 'scripts' => array( 'modules/ZeroOverlay.js',
'modules/carrierConfig.js', 'modules/banner.js', 'modules/interstitial.js',
'modules/redux.js' ),
+ 'messages' => array(
+ 'zero-rated-mobile-access-charge-auth',
+ 'zero-rated-mobile-access-banner-text-data-charges-yes',
+ 'zero-rated-mobile-access-banner-text-data-charges-no'
+ )
);
$wgResourceModules['zero.config'] = array(
diff --git a/includes/ApiZeroConfig.php b/includes/ApiZeroConfig.php
index 08fea8c..2db0062 100644
--- a/includes/ApiZeroConfig.php
+++ b/includes/ApiZeroConfig.php
@@ -36,6 +36,7 @@
$result->addValue( null, 'showImages',
$config['showImages'] );
$result->addValue( null,
'whitelistedLangs', $config['whitelistedLangs'] );
$result->addValue( null, 'enableHttps',
$config['enableHttps'] );
+ $result->addValue( null, 'sites',
$config['sites'] );
} else {
$result->addValue( null, 'enabled',
false );
}
diff --git a/modules/ZeroOverlay.js b/modules/ZeroOverlay.js
new file mode 100644
index 0000000..7d2dbbb
--- /dev/null
+++ b/modules/ZeroOverlay.js
@@ -0,0 +1,19 @@
+( function( M ) {
+ var Overlay = M.require( 'Overlay' ),
+ ZeroOverlay = Overlay.extend( {
+ template: M.template.get( 'interstitial' ),
+ closeOnBack: true,
+ defaults: {
+ yes: mw.msg(
'zero-rated-mobile-access-banner-text-data-charges-yes' ),
+ no: mw.msg(
'zero-rated-mobile-access-banner-text-data-charges-no' ),
+ warning: mw.msg( 'zero-rated-mobile-access-charge-auth' )
+ }
+ } );
+
+ M.router.route( /^interstitial\/(.*)/, function( url ) {
+ new ZeroOverlay( { url: url } ).show();
+ } );
+
+ M.define( 'ZeroOverlay', ZeroOverlay );
+
+}( mw.mobileFrontend ) );
\ No newline at end of file
diff --git a/modules/carrierConfig.js b/modules/carrierConfig.js
new file mode 100644
index 0000000..0b3cc59
--- /dev/null
+++ b/modules/carrierConfig.js
@@ -0,0 +1,4 @@
+( function( M ) {
+ var api = M.require( 'api' );
+ M.define( 'carrierConfig', api.get( { action: 'zeroconfig', type: 'config'
} ) );
+}( mw.mobileFrontend ) );
\ No newline at end of file
diff --git a/modules/interstitial.js b/modules/interstitial.js
new file mode 100644
index 0000000..e59cc6d
--- /dev/null
+++ b/modules/interstitial.js
@@ -0,0 +1,86 @@
+( function ( M, $ ) {
+ var httpsProxyingEnhanced = false, /* whether Varnish handles HTTPS nicely
*/
+ isHttpsFree = false, /* declaration for whether carrier's config and
Varnish make it free */
+ zeroRe = /renderZeroRatedRedirect=true/, /* legacy interstitial link
indicator */
+ fromRe = /./, /* legacy interstitial link FROM indicator (wildcard) */
+ toRe = /[&?]returnto=([^&]+)/, /* legacy interstitial link TO
indicator */
+ zeroReModern = /Special:ZeroRatedMobileAccess(.+)$/, /* new
interstitial link indicator */
+ fromReModern = /[&?]from=([^&]+)/, /* new interstitial FROM indicator
*/
+ toReModern = /[&?]to=([^&]+)/, /* new interstitial TO indicator */
+ wikipediaRe =
/^(http:\/\/|https:\/\/|\/\/)([^.]+)\.([^.]+\.[^.]+)\.org/, /* hypothetically,
a Wikipedia (actually Wikimedia) URL (more restrictions below) */
+ isCurrentlyHttps = window.location.protocol.toLowerCase() ===
'https:', /* whether user is on an insecure http:// page */
+ areImagesFree = false,
+ ZeroOverlay = M.require( 'ZeroOverlay' ),
+ carrierConf = M.require( 'carrierConfig' );
+
+ $( function () {
+
+ carrierConf.done( function( conf ) {
+ var allLangsFree = false, /* variable declaration saying we don't
which languages are free yet */
+ freeLangs = [], /* variable declaration of free languages,
which we don't know yet */
+ sites = []; /* variable declaration of whether mdot or zerodot
are free, which we don't know yet */
+
+ if ( conf.enableHttps !== undefined && conf.enableHttps === true )
{
+ isHttpsFree = httpsProxyingEnhanced;
+ }
+
+ if ( conf.whitelistedLangs ) {
+ if ( conf.whitelistedLangs.length === 0 ) {
+ allLangsFree = true;
+ } else {
+ freeLangs = conf.whitelistedLangs;
+ }
+ }
+
+ if ( conf.sites ) {
+ sites = conf.sites;
+ }
+
+
+ if ( conf.showImages ) {
+ areImagesFree = true;
+ }
+
+ $( 'a' ).on( 'click', function ( ev ) {
+ var $eventTarget = $( this ), /* onclick element */
+ dest = $eventTarget.prop( 'href' ), /* actual url of
hyperlink */
+ destParts = [], /* declaration to contain split up URL */
+ match = toRe.exec( dest ), /* whether this link looks
legacy redirecty */
+ matchModern = toReModern.exec( dest ), /* whether this
link looks redirecty on the new system */
+ regexesPassed = dest && zeroRe.test( dest ) &&
fromRe.test( dest ) && match !== null, /* whether the link is legacy formatted
for interstitials */
+ regexesPassedModern = dest && zeroReModern.test( dest ) &&
fromReModern.test( dest ) && matchModern !== null, /* whether the link is
modernly formatted for interstitials */
+ extractedUrl = '', /* variable declaration to eventually
extract the appropriate destination URL */
+ subdomainWhitelisted = false, /* declaration that until
proven otherwise destination links are unsafe */
+ uriSchemeSafe = false, /* declaration that until proven
otherwise the destination link's scheme is unsafe */
+ interstitialRequired = true; /* interstitial is necessary
until proven otherwise */
+
+ if ( regexesPassed || regexesPassedModern ) {
+ extractedUrl = regexesPassedModern ? matchModern[1] :
match[1];
+ destParts = wikipediaRe.exec( extractedUrl );
+ if ( destParts !== null ) {
+
+ subdomainWhitelisted = ( allLangsFree ||
freeLangs.indexOf( destParts[2] ) !== -1 ) &&
+ sites.indexOf( destParts[3] ) !== -1 ;
+
+ uriSchemeSafe = destParts[1] !== 'https://' ||
isHttpsFree || isCurrentlyHttps;
+
+ if ( subdomainWhitelisted && uriSchemeSafe ) {
+ interstitialRequired = false;
+ }
+
+ }
+
+ if ( areImagesFree && $eventTarget.hasClass( 'image' ) &&
extractedUrl.test( /\/[^\/]]/ ) ) {
+ interstitialRequired = false;
+ }
+
+ if ( interstitialRequired ) {
+ window.location.hash = '#interstitial/' +
decodeURIComponent( extractedUrl );
+ ev.preventDefault();
+ }
+ }
+ } );
+
+ } );
+ } );
+}( mw.mobileFrontend, jQuery ) );
\ No newline at end of file
diff --git a/modules/redux.js b/modules/redux.js
new file mode 100644
index 0000000..f5d178a
--- /dev/null
+++ b/modules/redux.js
@@ -0,0 +1,53 @@
+( function ( M, $ ) {
+ var httpsProxyingEnhanced = false,
+ isMdot = document.location.hostname.toLowerCase().search(
/\.m\.wikipedia\.org$/ ) !== -1,
+ isCleartext = document.location.protocol.toLowerCase() === 'http:',
+ ZeroOverlay = M.require( 'ZeroOverlay' );
+
+ $( function () {
+ var carrierConf = M.require( 'carrierConfig' ),
+ conf = {},
+ isHttpsFree = false;
+
+ carrierConf.done( function( conf ) {
+
+ if ( conf.enableHttps !== undefined && conf.enableHttps === true )
{
+ isHttpsFree = httpsProxyingEnhanced;
+ }
+
+ if ( !isCleartext && !isHttpsFree ) {
+ /* we can't hide by default in CSS b/c of feature phones */
+ $( '#zero-rated-banner' ).hide();
+ }
+
+ if ( isCleartext && !isHttpsFree ) {
+ /* TODO: once history page not Desktop-y, remove this */
+ $( '#mw-mf-last-modified' ).on( 'click', function ( ev ) {
+ var that = this;
+ window.location.hash = '#interstitial/' + $( that ).attr(
'href' );
+ ev.preventDefault();
+ } );
+ }
+
+ if ( isMdot ) {
+ /* CSS isn't working for this element, and !important breaks
stuff */
+ $( '.icon-settings' ).show();
+ }
+
+ if ( isHttpsFree ) {
+ if ( isMdot ) {
+ /*
+ FIXME: jdlrobson in change 83133 - "Maybe
MobileFrontend can make this
+ easier by marking these links with a shared class so
you can do something
+ like $( '.httpsLink' ).show();"
+ */
+ $(
'.icon-uploads,.icon-watchlist,.icon-loginout,#ca-upload' ).show();
+
+ }
+
+ $( '#page-actions' ).show();
+ }
+
+ } );
+ } );
+}( mw.mobileFrontend, jQuery ) );
\ No newline at end of file
diff --git a/modules/redux.less b/modules/redux.less
new file mode 100644
index 0000000..8df872e
--- /dev/null
+++ b/modules/redux.less
@@ -0,0 +1,14 @@
+#page-actions,
+.icon-watchlist,
+.icon-settings,
+.icon-loginout,
+.icon-nearby,
+.icon-uploads,
+#ca-upload,
+/* next line is on settings page */
+.mw-mf-settings-description,
+/* next two lines for the settings page (requires good CSS support, though) */
+.mw-mf-settings > ul:nth-child(2) > li:nth-child(2),
+.mw-mf-settings > ul:nth-child(2) > li:nth-child(4) {
+ display:none !important;
+}
\ No newline at end of file
diff --git a/templates/interstitial.html b/templates/interstitial.html
new file mode 100644
index 0000000..3c6bcab
--- /dev/null
+++ b/templates/interstitial.html
@@ -0,0 +1,7 @@
+<div class="header mw-mf-banner mw-mf-banner-undismissable">
+{{warning}}
+</div>
+<div class="button-bar button-bar-centered buttonBar">
+ <a href="{{url}}" class="button">{{yes}}</a>
+ <button class="cancel inline">{{no}}</button>
+</div>
\ No newline at end of file
--
To view, visit https://gerrit.wikimedia.org/r/83133
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Icd8c9140e3a22de60e148670f7bbc67a356950d8
Gerrit-PatchSet: 39
Gerrit-Project: mediawiki/extensions/ZeroRatedMobileAccess
Gerrit-Branch: master
Gerrit-Owner: Dr0ptp4kt <[email protected]>
Gerrit-Reviewer: Awjrichards <[email protected]>
Gerrit-Reviewer: Dfoy <[email protected]>
Gerrit-Reviewer: Dr0ptp4kt <[email protected]>
Gerrit-Reviewer: JGonera <[email protected]>
Gerrit-Reviewer: Jdlrobson <[email protected]>
Gerrit-Reviewer: Kaldari <[email protected]>
Gerrit-Reviewer: Yurik <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits