Florianschmidtwelzow has uploaded a new change for review.

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

Change subject: Initial commit
......................................................................

Initial commit

First version of OOJsUIAjaxLogin with basic functionality.

Change-Id: I8b32a8482f96908bbdfef2130ecca07e2ed3e5de
---
A LICENSE
A OOJsUIAjaxLogin.php
A i18n/en.json
A i18n/qqq.json
A includes/OOJsUIAjaxLogin.hooks.php
A resources/Resources.php
A resources/ext.OOJsUIAjaxLogin.init/init.js
A resources/ext.OOJsUIAjaxLogin.overlay/LoginOverlay.js
A resources/ext.OOJsUIAjaxLogin.overlay/LoginOverlay.less
9 files changed, 464 insertions(+), 0 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/OOJsUIAjaxLogin 
refs/changes/56/207756/1

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d37a2f3
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Florian Schmidt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/OOJsUIAjaxLogin.php b/OOJsUIAjaxLogin.php
new file mode 100644
index 0000000..7be12f7
--- /dev/null
+++ b/OOJsUIAjaxLogin.php
@@ -0,0 +1,49 @@
+<?php
+/**
+The MIT License (MIT)
+
+Copyright (c) 2015 Florian Schmidt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+       die( 'This is an extension for Mediawiki and can not run standalone.' );
+}
+
+$wgExtensionCredits['other'][] = array(
+       'path' => __FILE__,
+       'name' => 'OOJsUIAjaxLogin',
+       'author' => 'Florian Schmidt',
+       'url' => 'https://www.mediawiki.org/wiki/Extension:OOJsUIAjaxLogin',
+       'descriptionmsg' => 'oojsuiajaxlogin-desc',
+       'version'  => '0.0.1',
+       'license-name' => "MIT",
+);
+
+// Autoload Classes
+$wgAutoloadClasses['OOJsUIAjaxLoginHooks'] = __DIR__ . 
'/includes/OOJsUIAjaxLogin.hooks.php';
+
+// message dir
+$wgMessagesDirs['OOJsUIAjaxLogin'] = __DIR__ . '/i18n';
+
+// Hooks
+$wgHooks['BeforePageDisplay'][] = 'OOJsUIAjaxLoginHooks::onBeforePageDisplay';
+
+require __DIR__ . '/resources/Resources.php';
diff --git a/i18n/en.json b/i18n/en.json
new file mode 100644
index 0000000..c44a7f9
--- /dev/null
+++ b/i18n/en.json
@@ -0,0 +1,9 @@
+{
+    "@metadata": {
+        "authors": [
+            "Florian Schmidt"
+        ]
+    },
+       "oojsuiajaxlogin-desc": "Adds an Ajax Login overlay to MediaWiki.",
+       "oojsuiajaxlogin-loading": "Loading..."
+}
diff --git a/i18n/qqq.json b/i18n/qqq.json
new file mode 100644
index 0000000..7098ee7
--- /dev/null
+++ b/i18n/qqq.json
@@ -0,0 +1,9 @@
+{
+       "@metadata": {
+               "authors": [
+                       "Florian Schmidt"
+               ]
+       },
+       "oojsuiajaxlogin-desc": "{{doc-special|OOHsUIAjaxLOgin}}",
+       "oojsuiajaxlogin-loading": "Test for the login link used to indicate, 
that the Ajax login overlay is loading."
+}
diff --git a/includes/OOJsUIAjaxLogin.hooks.php 
b/includes/OOJsUIAjaxLogin.hooks.php
new file mode 100644
index 0000000..2e6d80a
--- /dev/null
+++ b/includes/OOJsUIAjaxLogin.hooks.php
@@ -0,0 +1,16 @@
+<?php
+
+class OOJsUIAjaxLoginHooks {
+       /**
+        * BeforePageDisplay hook handler. Add the required module for this 
extension.
+        *
+        * @param OutputPage $out
+        * @param Skin $sk
+        */
+       public static function onBeforePageDisplay( OutputPage &$out, Skin &$sk 
) {
+               $out->addModules( array(
+                               'ext.OOJsUIAjaxLogin.init'
+                       )
+               );
+       }
+}
diff --git a/resources/Resources.php b/resources/Resources.php
new file mode 100644
index 0000000..bad6843
--- /dev/null
+++ b/resources/Resources.php
@@ -0,0 +1,45 @@
+<?php
+// Resource template
+$wgResourceTemplate = array(
+       'localBasePath' => __DIR__,
+       'remoteExtPath' => 'OOJsUIAjaxLogin/resources',
+);
+// Resource modules
+$wgResourceModules += array(
+       'ext.OOJsUIAjaxLogin.init' => $wgResourceTemplate + array(
+               'scripts' => array(
+                       'ext.OOJsUIAjaxLogin.init/init.js',
+               ),
+               'messages' => array(
+                       'oojsuiajaxlogin-loading',
+               ),
+       ),
+       'ext.OOJsUIAjaxLogin.overlay' => $wgResourceTemplate + array(
+               'dependencies' => array(
+                       'oojs-ui',
+                       'mediawiki.api',
+                       'mediawiki.jqueryMsg',
+               ),
+               'scripts' => array(
+                       'ext.OOJsUIAjaxLogin.overlay/LoginOverlay.js',
+               ),
+               'styles' => array(
+                       'ext.OOJsUIAjaxLogin.overlay/LoginOverlay.less',
+               ),
+               'messages' => array(
+                       'login',
+                       'wrongpassword',
+                       'userlogin-yourname',
+                       'userlogin-yourname-ph',
+                       'userlogin-yourpassword',
+                       'userlogin-yourpassword-ph',
+                       'pt-login-button',
+                       'userlogin-joinproject',
+                       'cancel',
+                       'welcomeuser',
+                       'unknown-error',
+               ),
+       ),
+);
+
+unset( $wgResourceTemplate );
diff --git a/resources/ext.OOJsUIAjaxLogin.init/init.js 
b/resources/ext.OOJsUIAjaxLogin.init/init.js
new file mode 100644
index 0000000..125126a
--- /dev/null
+++ b/resources/ext.OOJsUIAjaxLogin.init/init.js
@@ -0,0 +1,24 @@
+( function ( $ ) {
+       // add click event listener to login link in personal tools
+       $( '#pt-login a' ).on( 'click', function ( ev ) {
+               var $el = $( ev.target ),
+                       oldEl;
+
+               // don't navigate to Special:UserLogin
+               ev.preventDefault();
+               // replace login link with a loading text to indicate, that the 
login form is loading
+               oldEl = $el.after(
+                       '<span id="oojsui-ajaxlogin">' + mw.msg( 
'oojsuiajaxlogin-loading' ) + '</span>'
+               ).detach();
+               // load the overlay module and show the overlay
+               mw.loader.using( 'ext.OOJsUIAjaxLogin.overlay', function () {
+                       mw.OOJsUIAjaxLogin.show();
+               }, function () {
+                       // if the module could not be loaded, navigate to the 
original target
+                       window.location.href = ev.target.href;
+               } ).then( function () {
+                       // replace the loading text with the old login link
+                       $( '#oojsui-ajaxlogin' ).replaceWith( oldEl );
+               } );
+       } );
+} ( jQuery ) );
diff --git a/resources/ext.OOJsUIAjaxLogin.overlay/LoginOverlay.js 
b/resources/ext.OOJsUIAjaxLogin.overlay/LoginOverlay.js
new file mode 100644
index 0000000..1a88ad6
--- /dev/null
+++ b/resources/ext.OOJsUIAjaxLogin.overlay/LoginOverlay.js
@@ -0,0 +1,286 @@
+( function ( $ ) {
+       // Create and append a window manager, which will open and close the 
window.
+       var windowManager = new OO.ui.WindowManager();
+       $( 'body' ).append( windowManager.$element );
+
+       mw.OOJsUIAjaxLogin = {
+               /**
+                * @var {null|OO.ui.MessageDialog} save the created overlay 
from setup
+                */
+               overlay: false,
+               /**
+                * @var {Number} loginRetry How often the login was retried 
(after 3 times, the login will be aborted)
+                */
+               loginRetry: 0,
+               /**
+                * @var {Boolean} loginLock Is there already a login process?
+                */
+               loginLock: false,
+
+               /**
+                * Setup the login overlay with all required fields, buttons 
and inputs.
+                * Resulting Ovleray will be saved in this.overlay.
+                */
+               setup: function () {
+                       var self = this;
+
+                       // initialize api to try to login later
+                       this.api = new mw.Api;
+
+                       /**
+                        * Constructor for LoginOverlay MessageDialog
+                        * @param {Object} config Configuration parameters
+                        */
+                       function LoginOverlay( config ) {
+                               LoginOverlay.super.call( this, config );
+                       }
+                       // inherit MessageDialog to LoginOverlay
+                       OO.inheritClass( LoginOverlay, OO.ui.MessageDialog );
+
+                       // Set title to message from Special:UserLogin
+                       LoginOverlay.static.title = mw.msg( 'login' );
+
+                       // Default actions for this overlay
+                       LoginOverlay.static.actions = [
+                               {
+                                       action: 'login',
+                                       label: mw.msg( 'pt-login-button' ),
+                                       flags: [ 'primary', 'constructive' ]
+                               },
+                               {
+                                       action: 'register',
+                                       label: mw.msg( 'userlogin-joinproject' 
),
+                                       flags: [ 'progressive' ]
+                               },
+                               {
+                                       action: 'cancel',
+                                       label: mw.msg( 'cancel' ),
+                                       flags: [ 'safe', 'destructive' ]
+                               }
+                       ];
+
+                       /**
+                        * Handles a click on one of the defined actions for 
this overlay.
+                        */
+                       LoginOverlay.prototype.getActionProcess = function ( 
action ) {
+                               // don't do anything, if there is already a 
login process
+                               if ( self.loginLock ) {
+                                       return new OO.ui.Process( function () { 
return false }, this );
+                               }
+                               switch ( action ) {
+                                       // login action, try a login with the 
data provided in the input fields
+                                       case 'login':
+                                               // lock the login process to 
don't do a login twice at the same time
+                                               self.loginLock = true;
+                                               // hide all fields and show the 
progress bar + resize the dialog
+                                               this.fieldset.toggle( false );
+                                               this.loginProgressBar.toggle( 
true );
+                                               this.updateSize();
+                                               return new OO.ui.Process( 
self.tryLogin(
+                                                       
this.usernameInput.getValue(),
+                                                       
this.passwordInput.getValue(),
+                                                       this
+                                               ), this );
+                                               break;
+                                       case 'register':
+                                               // create the login link 
parameters
+                                               var params = {
+                                                               returnto: 
mw.config.get( 'wgPageName' )
+                                                       },
+                                                       signupParams ={
+                                                               type: 'signup'
+                                                       };
+
+                                               // navigate to 
Special:UserLogin/signup
+                                               window.location.href = 
mw.util.getUrl( 'Special:UserLogin', $.extend( params, signupParams ) );
+                                               return;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               // Fallback to parent handler
+                               return 
LoginOverlay.super.prototype.getActionProcess.call( this, action );
+                       };
+
+                       /**
+                        * Initialize the overlay, create input fields and 
labels and so on.
+                        */
+                       LoginOverlay.prototype.initialize = function () {
+                               var progressBarFieldset = new 
OO.ui.FieldsetLayout();
+
+                               // Call the parent method
+                               LoginOverlay.super.prototype.initialize.call( 
this );
+
+                               // create input fields
+                               this.usernameInput = new OO.ui.TextInputWidget( 
{
+                                       placeholder: mw.msg( 
'userlogin-yourname-ph' )
+                               } ),
+                               this.passwordInput = new OO.ui.TextInputWidget( 
{
+                                       placeholder: mw.msg( 
'userlogin-yourpassword-ph' ),
+                                       type: 'password'
+                               } );
+                               // create a field for error messages and hide 
it by default
+                               this.errorMessageContainer = new 
OO.ui.LabelWidget( {
+                                       label: '',
+                                       classes: [ 'errorbox', 
'oojsui-ajaxlogin' ]
+                               } );
+                               this.errorMessageContainer.toggle( false );
+                               // same for a progress bar
+                               this.loginProgressBar = new 
OO.ui.ProgressBarWidget();
+                               this.loginProgressBar.toggle( false );
+
+                               progressBarFieldset.addItems( [
+                                       new OO.ui.FieldLayout( 
this.loginProgressBar, {
+                                               align: 'top'
+                                       } )
+                               ] );
+                               // Create a fieldset for the input fields.
+                               this.fieldset = new OO.ui.FieldsetLayout();
+
+                               // add input fields to the fieldset
+                               this.fieldset.addItems( [
+                                       new OO.ui.FieldLayout( 
this.usernameInput, {
+                                               label: mw.msg( 
'userlogin-yourname' ),
+                                               align: 'top'
+                                       } ),
+                                       new OO.ui.FieldLayout( 
this.passwordInput, {
+                                               label: mw.msg( 
'userlogin-yourpassword' ),
+                                               align: 'top'
+                                       } ),
+                                       new OO.ui.FieldLayout( 
this.errorMessageContainer, {
+                                               align: 'top'
+                                       } )
+                               ] );
+
+                               // set the content
+                               this.content = new OO.ui.PanelLayout( { $: 
this.$, padded: true, expanded: false } );
+                               this.content.$element.append(
+                                       this.title.$element,
+                                       this.fieldset.$element,
+                                       progressBarFieldset.$element
+                               );
+                               this.$body.append( this.content.$element );
+                       };
+
+                       /**
+                        * @inheritdoc
+                        */
+                       LoginOverlay.prototype.getReadyProcess = function ( 
data ) {
+                               var self = this;
+                               // make sure, that username input field is 
focused
+                               return 
LoginOverlay.super.prototype.getReadyProcess.call( this, data )
+                                       .next( function () {
+                                               self.usernameInput.focus();
+                                       } );
+                       }
+                       // Override the getBodyHeight() method to specify a 
custom height (or don't to use the automatically generated height)
+                       LoginOverlay.prototype.getBodyHeight = function () {
+                               // get the height of the body and let some 
place for error messages
+                               return this.content.$element.outerHeight( true 
);
+                       };
+
+                       // Create a new LoginOverlay and save it to this.overlay
+                       this.overlay = new LoginOverlay({
+                               size: 'large'
+                       });
+
+                       // Add the window to the window manager using the 
addWindows() method
+                       windowManager.addWindows( [ this.overlay ] );
+               },
+
+               /**
+                * Setup a new overlay (if needed) and show it with the 
windowManager
+                */
+               show: function () {
+                       if ( !this.overlay ) {
+                               this.setup();
+                       }
+                       // Open the window!
+                       windowManager.openWindow( this.overlay );
+               },
+
+               /**
+                * Try to login with the given data through the Api.
+                * @param {String} username Plain User name
+                * @param {String} password Plain Password
+                * @param {LoginOverlay} ov The LoginOverlay object where this 
function is called from
+                * @param {String} [token] Optional logintoken provided by the 
login api
+                */
+               tryLogin: function ( username, password, ov, token ) {
+                       var self = this;
+
+                       // make the request
+                       this.api.post( {
+                               action: 'login',
+                               lgname: username,
+                               lgpassword: password,
+                               lgtoken: token
+                       } ).done( function ( data ) {
+                               // check, if this is the 6 try to the login api 
and if so, don't do anything
+                               if ( self.loginRetry < 6 && 
data.login.hasOwnProperty( 'result' ) ) {
+                                       // check, if the login was successful 
or handle errors
+                                       switch ( data.login.result ) {
+                                               case 'NeedToken':
+                                                       // the first call to 
the api returns a token to call the Api again to
+                                                       // really try to login
+                                                       // increase the login 
try counter
+                                                       self.loginRetry++;
+                                                       // try again, now with 
the required token
+                                                       return self.tryLogin( 
username, password, ov, data.login.token );
+                                                       break;
+                                               case 'Success':
+                                                       // The user was logged 
in successfully, show a welcome message and reload
+                                                       // this page
+                                                       var welcomeWidget = 
label1 = new OO.ui.LabelWidget( {
+                                                                       label: 
mw.msg( 'welcomeuser', data.login.lgusername )
+                                                               } );
+
+                                                       
ov.loginProgressBar.toggle( false );
+                                                       
ov.content.$element.append(
+                                                               
welcomeWidget.$element
+                                                       );
+                                                       ov.updateSize();
+                                                       
window.location.reload();
+                                                       break;
+                                               default:
+                                                       // the default is: 
false password, try again
+                                                       self.loginRetry = 0;
+                                                       return 
self.addErrorMessage( ov, mw.msg( 'wrongpassword' ) );
+                                                       break;
+                                       }
+                               } else {
+                                       // navigate to the full login page
+                                       var params = {
+                                                       returnto: 
mw.config.get( 'wgPageName' )
+                                               };
+
+                                       // navigate to Special:UserLogin
+                                       window.location.href = mw.util.getUrl( 
'Special:UserLogin', params );
+                               }
+                       } ).fail( function () {
+                               // unknown error
+                               // FIXME: i18n & better error handling
+                               self.addErrorMessage( ov, mw.msg( 
'unknown-error' ) );
+                       } ).always( function () {
+                               // reset loginLock to allow a new login try
+                               self.loginLock = false;
+                       } );
+               },
+
+               /**
+                * Adds an errorbox to the provided login form with the 
provided message and turns off any progressbar.
+                * @param {LoginOverlay} ov LoginOverlay object to show the 
errorbox on
+                * @param {String} msg Error text
+                * @return {boolean} always returns false
+                */
+               addErrorMessage: function ( ov, msg ) {
+                       ov.loginProgressBar.toggle( false );
+                       ov.fieldset.toggle( true );
+                       ov.errorMessageContainer.$element.text( msg );
+                       ov.errorMessageContainer.toggle( true );
+                       ov.updateSize();
+                       return false;
+               }
+       };
+
+} ( jQuery ) );
\ No newline at end of file
diff --git a/resources/ext.OOJsUIAjaxLogin.overlay/LoginOverlay.less 
b/resources/ext.OOJsUIAjaxLogin.overlay/LoginOverlay.less
new file mode 100644
index 0000000..d707596
--- /dev/null
+++ b/resources/ext.OOJsUIAjaxLogin.overlay/LoginOverlay.less
@@ -0,0 +1,5 @@
+// limit all changes to the errorbox to our overlay
+.oojsui-ajaxlogin.errorbox {
+       display: block;
+       text-align: center;
+}

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I8b32a8482f96908bbdfef2130ecca07e2ed3e5de
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/OOJsUIAjaxLogin
Gerrit-Branch: master
Gerrit-Owner: Florianschmidtwelzow <florian.schmidt.wel...@t-online.de>

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

Reply via email to