http://www.mediawiki.org/wiki/Special:Code/MediaWiki/95676
Revision: 95676
Author: neilk
Date: 2011-08-29 16:20:14 +0000 (Mon, 29 Aug 2011)
Log Message:
-----------
re-copied state of UploadWizard in 1.17wmf1 @ 95537. Reverted reverts of
resources and includes in 95285, necessary to get UploadCampaigns working,
include mediawiki.uri.js library
Modified Paths:
--------------
branches/wmf/1.17wmf1/includes/HTMLForm.php
branches/wmf/1.17wmf1/includes/Message.php
branches/wmf/1.17wmf1/includes/SpecialPage.php
branches/wmf/1.17wmf1/resources/Resources.php
Added Paths:
-----------
branches/wmf/1.17wmf1/extensions/UploadWizard/
branches/wmf/1.17wmf1/resources/mediawiki/mediawiki.uri.js
Modified: branches/wmf/1.17wmf1/includes/HTMLForm.php
===================================================================
--- branches/wmf/1.17wmf1/includes/HTMLForm.php 2011-08-29 16:12:17 UTC (rev
95675)
+++ branches/wmf/1.17wmf1/includes/HTMLForm.php 2011-08-29 16:20:14 UTC (rev
95676)
@@ -369,10 +369,16 @@
* @return String wrapped HTML.
*/
function wrapForm( $html ) {
+ global $wgUserLanguage;
# Include a <fieldset> wrapper for style, if requested.
if ( $this->mWrapperLegend !== false ) {
- $html = Xml::fieldset( $this->mWrapperLegend, $html );
+ if ( is_a( $this->mWrapperLegend, 'Message' ) ) {
+ $legend = $this->mWrapperLegend->toString();
+ } else {
+ $legend = $this->mWrapperLegend;
+ }
+ $html = Xml::fieldset( $legend, $html );
}
# Use multipart/form-data
$encType = $this->mUseMultipart
Modified: branches/wmf/1.17wmf1/includes/Message.php
===================================================================
--- branches/wmf/1.17wmf1/includes/Message.php 2011-08-29 16:12:17 UTC (rev
95675)
+++ branches/wmf/1.17wmf1/includes/Message.php 2011-08-29 16:20:14 UTC (rev
95676)
@@ -357,4 +357,4 @@
return $this->message;
}
-}
\ No newline at end of file
+}
Modified: branches/wmf/1.17wmf1/includes/SpecialPage.php
===================================================================
--- branches/wmf/1.17wmf1/includes/SpecialPage.php 2011-08-29 16:12:17 UTC
(rev 95675)
+++ branches/wmf/1.17wmf1/includes/SpecialPage.php 2011-08-29 16:20:14 UTC
(rev 95676)
@@ -937,7 +937,148 @@
}
}
+
/**
+ * Special page which uses an HTMLForm to handle processing. This is mostly a
+ * clone of FormAction. More special pages should be built this way; maybe
this could be
+ * a new structure for SpecialPages
+ */
+abstract class FormSpecialPage extends SpecialPage {
+
+ /**
+ * Get an HTMLForm descriptor array
+ * @return Array
+ */
+ protected abstract function getFormFields();
+
+ /**
+ * Add pre- or post-text to the form
+ * @return String HTML which will be sent to $form->addPreText()
+ */
+ protected function preText() { return ''; }
+ protected function postText() { return ''; }
+
+ /**
+ * Play with the HTMLForm if you need to more substantially
+ * @param $form HTMLForm
+ */
+ protected function alterForm( HTMLForm $form ) {}
+
+ /**
+ * Get the HTMLForm to control behaviour
+ * @return HTMLForm|null
+ */
+ protected function getForm() {
+ global $wgRequest;
+ $this->fields = $this->getFormFields();
+
+ $form = new HTMLForm( $this->fields );
+ $form->setTitle( $this->getTitle() );
+
+ $form->setSubmitCallback( array( $this, 'onSubmit' ) );
+ $form->setWrapperLegend( wfMessage( strtolower(
$this->getName() ) . '-legend' ) );
+ $form->addHeaderText(
+ wfMessage( strtolower( $this->getName() ) . '-text'
)->parseAsBlock() );
+
+ // Retain query parameters (uselang etc)
+ $params = array_diff_key( $_GET, array( 'title' => null ) );
+ $form->addHiddenField( 'redirectparams', wfArrayToCGI( $params
) );
+
+ $form->addPreText( $this->preText() );
+ $form->addPostText( $this->postText() );
+ $this->alterForm( $form );
+
+ // Give hooks a chance to alter the form, adding extra fields
or text etc
+ wfRunHooks( "Special{$this->getName()}BeforeFormDisplay",
array( &$form ) );
+
+ return $form;
+ }
+
+ /**
+ * Process the form on POST submission.
+ * @param $data Array
+ * @return Bool|Array true for success, false for didn't-try, array of
errors on failure
+ */
+ public abstract function onSubmit( array $data );
+
+ /**
+ * Do something exciting on successful processing of the form, most
likely to show a
+ * confirmation message
+ */
+ public abstract function onSuccess();
+
+ /**
+ * Basic SpecialPage workflow: get a form, send it to the user; get
some data back,
+ *
+ * @param $par String Subpage string if one was specified
+ */
+ public function execute( $par ) {
+ global $wgUser;
+ $this->setParameter( $par );
+ $this->setHeaders();
+
+ // This will throw exceptions if there's a problem
+ $this->userCanExecute( $wgUser );
+
+ $form = $this->getForm();
+ if ( $form->show() ) {
+ $this->onSuccess();
+ }
+ }
+
+ /**
+ * Maybe do something interesting with the subpage parameter
+ * @param $par String
+ */
+ protected function setParameter( $par ){}
+
+ /**
+ * Checks if the given user (identified by an object) can perform this
action. Can be
+ * overridden by sub-classes with more complicated permissions schemes.
Failures here
+ * must throw subclasses of ErrorPageError
+ *
+ * @param $user User: the user to check, or null to use the context user
+ * @return Bool true
+ * @throws ErrorPageError
+ */
+ public function userCanExecute( $user ) {
+ if ( $this->requiresWrite() && wfReadOnly() ) {
+ throw new ReadOnlyError();
+ }
+
+ if ( $this->getRestriction() !== null && !$user->isAllowed(
$this->getRestriction() ) ) {
+ throw new PermissionsError( $this->getRestriction() );
+ }
+
+ if ( $this->requiresUnblock() && $user->isBlocked() ) {
+ $block = $user->mBlock;
+ throw new UserBlockedError( $block );
+ }
+
+ return true;
+ }
+
+ /**
+ * Whether this action requires the wiki not to be locked
+ * @return Bool
+ */
+ public function requiresWrite() {
+ return true;
+ }
+
+ /**
+ * Whether this action cannot be executed by a blocked user
+ * @return Bool
+ */
+ public function requiresUnblock() {
+ return true;
+ }
+}
+
+
+
+
+/**
* Shortcut to construct a special page which is unlisted by default
* @ingroup SpecialPage
*/
Modified: branches/wmf/1.17wmf1/resources/Resources.php
===================================================================
--- branches/wmf/1.17wmf1/resources/Resources.php 2011-08-29 16:12:17 UTC
(rev 95675)
+++ branches/wmf/1.17wmf1/resources/Resources.php 2011-08-29 16:20:14 UTC
(rev 95676)
@@ -342,6 +342,9 @@
'dependencies' => array( 'jquery.checkboxShiftClick',
'jquery.client', 'jquery.placeholder' ),
'debugScripts' =>
'resources/mediawiki.util/mediawiki.util.test.js',
),
+ 'mediawiki.Uri' => array(
+ 'scripts' => 'resources/mediawiki/mediawiki.uri.js',
+ ),
'mediawiki.action.history' => array(
'scripts' =>
'resources/mediawiki.action/mediawiki.action.history.js',
'dependencies' => 'mediawiki.legacy.history',
Copied: branches/wmf/1.17wmf1/resources/mediawiki/mediawiki.uri.js (from rev
95284, branches/wmf/1.17wmf1/resources/mediawiki/mediawiki.uri.js)
===================================================================
--- branches/wmf/1.17wmf1/resources/mediawiki/mediawiki.uri.js
(rev 0)
+++ branches/wmf/1.17wmf1/resources/mediawiki/mediawiki.uri.js 2011-08-29
16:20:14 UTC (rev 95676)
@@ -0,0 +1,260 @@
+/**
+ * Library for simple URI parsing and manipulation. Requires jQuery.
+ *
+ * Do not expect full RFC 3986 compliance. Intended to be minimal, but
featureful.
+ * The use cases we have in mind are constructing 'next page' or 'previous
page' URLs,
+ * detecting whether we need to use cross-domain proxies for an API,
constructing
+ * simple URL-based API calls, etc.
+ *
+ * Intended to compress very well if you use a JS-parsing minifier.
+ *
+ * Dependencies: mw, jQuery
+ *
+ * Example:
+ *
+ * var uri = new mw.Uri( 'http://foo.com/mysite/mypage.php?quux=2' );
+ *
+ * if ( uri.host == 'foo.com' ) {
+ * uri.host = 'www.foo.com';
+ * uri.extend( { bar: 1 } );
+ *
+ * $( 'a#id1' ).attr( 'href', uri );
+ * // anchor with id 'id1' now links to
http://foo.com/mysite/mypage.php?bar=1&quux=2
+ *
+ * $( 'a#id2' ).attr( 'href', uri.clone().extend( { bar: 3, pif: 'paf'
} ) );
+ * // anchor with id 'id2' now links to
http://foo.com/mysite/mypage.php?bar=3&quux=2&pif=paf
+ * }
+ *
+ * Parsing here is regex based, so may not work on all URIs, but is good
enough for most.
+ *
+ * Given a URI like
+ *
'http://usr:[email protected]:81/dir/dir.2/index.htm?q1=0&&test1&test2=&test3=value+%28escaped%29&r=1&r=2#top':
+ * The returned object will have the following properties:
+ *
+ * protocol 'http'
+ * user 'usr'
+ * password 'pwd'
+ * host 'www.test.com'
+ * port '81'
+ * path '/dir/dir.2/index.htm'
+ * query {
+ * q1: 0,
+ * test1: null,
+ * test2: '',
+ * test3: 'value (escaped)'
+ * r: [1, 2]
+ * }
+ * fragment 'top'
+ *
+ * n.b. 'password' is not technically allowed for HTTP URIs, but it is
possible with other
+ * sorts of URIs.
+ * You can modify the properties directly. Then use the toString() method to
extract the
+ * full URI string again.
+ *
+ * Parsing based on parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com>
MIT License
+ * http://stevenlevithan.com/demo/parseuri/js/
+ *
+ */
+
+( function( $ ) {
+
+ /**
+ * Function that's useful when constructing the URI string -- we
frequently encounter the pattern of
+ * having to add something to the URI as we go, but only if it's
present, and to include a character before or after if so.
+ * @param {String} to prepend, if value not empty
+ * @param {String} value to include, if not empty
+ * @param {String} to append, if value not empty
+ * @param {Boolean} raw -- if true, do not URI encode
+ * @return {String}
+ */
+ function cat( pre, val, post, raw ) {
+ if ( val === undefined || val === null || val === '' ) {
+ return '';
+ } else {
+ return pre + ( raw ? val : mw.Uri.encode( val ) ) +
post;
+ }
+ }
+
+ // Regular expressions to parse many common URIs.
+ var parser = {
+ strict:
/^(?:([^:\/?#]+):)?(?:\/\/(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)?((?:[^?#\/]*\/)*[^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
+ loose:
/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?((?:\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?[^?#\/]*)(?:\?([^#]*))?(?:#(.*))?/
+ },
+
+ // The order here matches the order of captured matches in the above
parser regexes.
+ properties = [
+ 'protocol', // http
+ 'user', // usr
+ 'password', // pwd
+ 'host', // www.test.com
+ 'port', // 81
+ 'path', // /dir/dir.2/index.htm
+ 'query', // q1=0&&test1&test2=value (will become { q1: 0,
test1: '', test2: 'value' } )
+ 'fragment' // top
+ ];
+
+ /**
+ * Constructs URI object. Throws error if arguments are
illegal/impossible, or otherwise don't parse.
+ * @constructor
+ * @param {!Object|String} URI string, or an Object with appropriate
properties (especially another URI object to clone). Object must have non-blank
'protocol', 'host', and 'path' properties.
+ * @param {Boolean} strict mode (when parsing a string)
+ */
+ mw.Uri = function( uri, strictMode ) {
+ strictMode = !!strictMode;
+ if ( uri !== undefined && uri !== null || uri !== '' ) {
+ if ( typeof uri === 'string' ) {
+ this._parse( uri, strictMode );
+ } else if ( typeof uri === 'object' ) {
+ var _this = this;
+ $.each( properties, function( i, property ) {
+ _this[property] = uri[property];
+ } );
+ if ( this.query === undefined ) {
+ this.query = {};
+ }
+ }
+ }
+ if ( !( this.protocol && this.host && this.path ) ) {
+ throw new Error( 'Bad constructor arguments' );
+ }
+ };
+
+ /**
+ * Standard encodeURIComponent, with extra stuff to make all browsers
work similarly and more compliant with RFC 3986
+ * Similar to rawurlencode from PHP and our JS library
mw.util.rawurlencode, but we also replace space with a +
+ * @param {String} string
+ * @return {String} encoded for URI
+ */
+ mw.Uri.encode = function( s ) {
+ return encodeURIComponent( s )
+ .replace( /!/g, '%21').replace( /'/g, '%27').replace(
/\(/g, '%28')
+ .replace( /\)/g, '%29').replace( /\*/g, '%2A')
+ .replace( /%20/g, '+' );
+ };
+
+ /**
+ * Standard decodeURIComponent, with '+' to space
+ * @param {String} string encoded for URI
+ * @return {String} decoded string
+ */
+ mw.Uri.decode = function( s ) {
+ return decodeURIComponent( s ).replace( /\+/g, ' ' );
+ };
+
+ mw.Uri.prototype = {
+
+ /**
+ * Parse a string and set our properties accordingly.
+ * @param {String} URI
+ * @param {Boolean} strictness
+ * @return {Boolean} success
+ */
+ _parse: function( str, strictMode ) {
+ var matches = parser[ strictMode ? 'strict' : 'loose'
].exec( str );
+ var uri = this;
+ $.each( properties, function( i, property ) {
+ uri[ property ] = matches[ i+1 ];
+ } );
+
+ // uri.query starts out as the query string; we will
parse it into key-val pairs then make
+ // that object the "query" property.
+ // we overwrite query in uri way to make cloning
easier, it can use the same list of properties.
+ var q = {};
+ // using replace to iterate over a string
+ if ( uri.query ) {
+ uri.query.replace(
/(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ($0, $1, $2, $3) {
+ if ( $1 ) {
+ var k = mw.Uri.decode( $1 );
+ var v = ( $2 === '' || $2 ===
undefined ) ? null : mw.Uri.decode( $3 );
+ if ( typeof q[ k ] === 'string'
) {
+ q[ k ] = [ q[ k ] ];
+ }
+ if ( typeof q[ k ] === 'object'
) {
+ q[ k ].push( v );
+ } else {
+ q[ k ] = v;
+ }
+ }
+ } );
+ }
+ this.query = q;
+ },
+
+ /**
+ * Returns user and password portion of a URI.
+ * @return {String}
+ */
+ getUserInfo: function() {
+ return cat( '', this.user, cat( ':', this.password, ''
) );
+ },
+
+ /**
+ * Gets host and port portion of a URI.
+ * @return {String}
+ */
+ getHostPort: function() {
+ return this.host + cat( ':', this.port, '' );
+ },
+
+ /**
+ * Returns the userInfo and host and port portion of the URI.
+ * In most real-world URLs, this is simply the hostname, but it
is more general.
+ * @return {String}
+ */
+ getAuthority: function() {
+ return cat( '', this.getUserInfo(), '@' ) +
this.getHostPort();
+ },
+
+ /**
+ * Returns the query arguments of the URL, encoded into a string
+ * Does not preserve the order of arguments passed into the
URI. Does handle escaping.
+ * @return {String}
+ */
+ getQueryString: function() {
+ var args = [];
+ $.each( this.query, function( key, val ) {
+ var k = mw.Uri.encode( key );
+ var vals = val === null ? [ null ] :
$.makeArray( val );
+ $.each( vals, function( i, v ) {
+ args.push( k + ( v === null ? '' : '='
+ mw.Uri.encode( v ) ) );
+ } );
+ } );
+ return args.join( '&' );
+ },
+
+ /**
+ * Returns everything after the authority section of the URI
+ * @return {String}
+ */
+ getRelativePath: function() {
+ return this.path + cat( '?', this.getQueryString(), '',
true ) + cat( '#', this.fragment, '' );
+ },
+
+ /**
+ * Gets the entire URI string. May not be precisely the same as
input due to order of query arguments.
+ * @return {String} the URI string
+ */
+ toString: function() {
+ return this.protocol + '://' + this.getAuthority() +
this.getRelativePath();
+ },
+
+ /**
+ * Clone this URI
+ * @return {Object} new URI object with same properties
+ */
+ clone: function() {
+ return new mw.Uri( this );
+ },
+
+ /**
+ * Extend the query -- supply query parameters to override or
add to ours
+ * @param {Object} query parameters in key-val form to override
or add
+ * @return {Object} this URI object
+ */
+ extend: function( parameters ) {
+ $.extend( this.query, parameters );
+ return this;
+ }
+ };
+
+} )( jQuery );
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs