r48740 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r48739‎ | r48740 | r48741 >
Date:14:18, 24 March 2009
Author:werdna
Status:deferred
Tags:
Comment:
Cute interface for doing EVERYTHING and the kitchen sink in HTML form land. Sample usage at http://p.defau.lt/?KGBw6ycvVMVtHO_0cQswDA
Modified paths:
  • /branches/preferences-work/phase3/includes/AutoLoader.php (modified) (history)
  • /branches/preferences-work/phase3/includes/HTMLForm.php (added) (history)

Diff [purge]

Index: branches/preferences-work/phase3/includes/HTMLForm.php
@@ -0,0 +1,360 @@
 2+<?php
 3+
 4+class HTMLForm {
 5+
 6+ /* The descriptor is an array of arrays.
 7+ i.e. array(
 8+ 'fieldname' => array( 'section' => 'section/subsection',
 9+ properties... ),
 10+ ...
 11+ )
 12+ */
 13+ function __construct( $descriptor, $messagePrefix ) {
 14+ $this->mMessagePrefix = $messagePrefix;
 15+
 16+ // Expand out into a tree.
 17+ $loadedDescriptor = array();
 18+ $this->mFlatFields = array();
 19+
 20+ foreach( $descriptor as $fieldname => $info ) {
 21+ $section = '';
 22+ if ( isset( $info['section'] ) )
 23+ $section = $info['section'];
 24+
 25+ $info['name'] = $fieldname;
 26+
 27+ $field = $this->loadInputFromParameters( $info );
 28+
 29+ $setSection =& $loadedDescriptor;
 30+ if ($section) {
 31+ $sectionParts = explode( '/', $section );
 32+
 33+ while( count($sectionParts) ) {
 34+ $newName = array_shift( $sectionParts );
 35+
 36+ if ( !isset($setSection[$newName]) ) {
 37+ $setSection[$newName] = array();
 38+ }
 39+
 40+ $setSection =& $setSection[$newName];
 41+ }
 42+ }
 43+ $setSection[$fieldname] = $field;
 44+ $this->mFlatFields[$fieldname] = $field;
 45+ }
 46+
 47+ $this->mFieldTree = $loadedDescriptor;
 48+ }
 49+
 50+ static function loadInputFromParameters( $descriptor ) {
 51+ // FIXME accept a friendlier type variable.
 52+ $class = $descriptor['class'];
 53+ $obj = new $class( $descriptor );
 54+
 55+ return $obj;
 56+ }
 57+
 58+ function show() {
 59+ $html = '';
 60+
 61+ // Load data from the request.
 62+ $this->loadData();
 63+
 64+ // Try a submission
 65+ $result = $this->trySubmit();
 66+
 67+ if ($result === true)
 68+ return $result;
 69+
 70+ // Display form.
 71+ $this->displayForm( $result );
 72+ }
 73+
 74+ /** Return values:
 75+ * TRUE == Successful submission
 76+ * FALSE == No submission attempted
 77+ * Anything else == Error to display.
 78+ */
 79+ function trySubmit() {
 80+ global $wgRequest, $wgUser;
 81+
 82+ $editToken = $wgRequest->getVal( 'wpEditToken' );
 83+
 84+ if ( !$wgUser->matchEditToken( $editToken ) ) {
 85+ return false;
 86+ }
 87+
 88+ $callback = $this->mSubmitCallback;
 89+
 90+ $res = call_user_func( $callback, $this->mFieldData );
 91+
 92+ return $res;
 93+ }
 94+
 95+ function setSubmitCallback( $cb ) {
 96+ $this->mSubmitCallback = $cb;
 97+ }
 98+
 99+ function displayForm( $submitResult ) {
 100+ global $wgUser, $wgOut;
 101+
 102+ if ( $submitResult !== false ) {
 103+ $this->displayErrors( $submitResult );
 104+ }
 105+
 106+ $html = $this->displaySection( $this->mFieldTree );
 107+
 108+ // Hidden fields
 109+ $html .= Xml::hidden( 'wpEditToken', $wgUser->editToken() );
 110+ $html .= Xml::hidden( 'title', $this->getTitle() );
 111+
 112+ $html .= Xml::submitButton( $this->getSubmitText() );
 113+
 114+ $html = Xml::tags( 'form',
 115+ array(
 116+ 'action' => $this->getTitle()->getFullURL(),
 117+ 'method' => 'post',
 118+ ),
 119+ $html );
 120+
 121+ $wgOut->addHTML( $html );
 122+ }
 123+
 124+ function displayErrors( $errors ) {
 125+ if ( is_array( $errors ) ) {
 126+ $errorstr = $this->formatErrors( $errors );
 127+ } else {
 128+ $errorstr = $errors;
 129+ }
 130+
 131+ $errorstr = Xml::tags( 'div', array( 'class' => 'error' ), $errorstr );
 132+
 133+ global $wgOut;
 134+ $wgOut->addHTML( $errorstr );
 135+ }
 136+
 137+ function formatErrors( $errors ) {
 138+ $errorstr = '';
 139+ foreach ( $errors as $error ) {
 140+ if (is_array($error)) {
 141+ $msg = array_shift($error);
 142+ } else {
 143+ $msg = $error;
 144+ $error = array();
 145+ }
 146+ $errorstr .= Xml::tags(
 147+ 'li',
 148+ null,
 149+ wfMsgExt( $msg, array( 'parseinline' ), $error )
 150+ );
 151+ }
 152+
 153+ $errorstr = Xml::tags( 'ul', null, $errorstr );
 154+
 155+ return $errorstr;
 156+ }
 157+
 158+ function setSubmitText( $t ) {
 159+ $this->mSubmitText = $t;
 160+ }
 161+
 162+ function getSubmitText() {
 163+ return $this->mSubmitText;
 164+ }
 165+
 166+ function setMessagePrefix( $p ) {
 167+ $this->mMessagePrefix = $p;
 168+ }
 169+
 170+ function setTitle( $t ) {
 171+ $this->mTitle = $t;
 172+ }
 173+
 174+ function getTitle() {
 175+ return $this->mTitle;
 176+ }
 177+
 178+ function displaySection( $fields ) {
 179+ $tableHtml = '';
 180+ $subsectionHtml = '';
 181+
 182+ foreach( $fields as $key => $value ) {
 183+ if ( is_object( $value ) ) {
 184+ $tableHtml .= $value->getTableRow( $this->mFieldData[$key] );
 185+ } elseif ( is_array( $value ) ) {
 186+ $section = $this->displaySection( $value );
 187+ $legend = wfMsg( "{$this->mMessagePrefix}-$key" );
 188+ $subsectionHtml .= Xml::fieldset( $legend, $section );
 189+ }
 190+ }
 191+
 192+ $tableHtml = "<table><tbody>\n$tableHtml</tbody></table>\n";
 193+
 194+ return $subsectionHtml . "\n" . $tableHtml;
 195+ }
 196+
 197+ function loadData() {
 198+ global $wgRequest;
 199+
 200+ $fieldData = array();
 201+
 202+ foreach( $this->mFlatFields as $fieldname => $field ) {
 203+ $fieldData[$fieldname] = $field->loadDataFromRequest( $wgRequest );
 204+ }
 205+
 206+ $this->mFieldData = $fieldData;
 207+ }
 208+}
 209+
 210+abstract class HTMLFormField {
 211+ abstract function getInputHTML( $value );
 212+
 213+ function loadDataFromRequest( $request ) {
 214+ if ($request->getCheck( $this->mName ) ) {
 215+ return $request->getText( $this->mName );
 216+ } else {
 217+ return $this->getDefault();
 218+ }
 219+ }
 220+
 221+ function __construct( $params ) {
 222+ $this->mParams = $params;
 223+
 224+ if (isset( $params['label-message'] ) ) {
 225+ $msgInfo = $params['label-message'];
 226+
 227+ if ( is_array( $msgInfo ) ) {
 228+ $msg = array_shift( $msgInfo );
 229+ } else {
 230+ $msg = $msgInfo;
 231+ $msgInfo = array();
 232+ }
 233+
 234+ $this->mLabel = wfMsgExt( $msg, 'parseinline', $msgInfo );
 235+ } elseif ( isset($params['label']) ) {
 236+ $this->mLabel = $params['label'];
 237+ }
 238+
 239+ if ( isset( $params['name'] ) ) {
 240+ $this->mName = 'wp'.$params['name'];
 241+ $this->mID = 'mw-input-'.$params['name'];
 242+ }
 243+
 244+ if ( isset( $params['default'] ) ) {
 245+ $this->mDefault = $params['default'];
 246+ }
 247+
 248+ if ( isset( $params['id'] ) ) {
 249+ $this->mID = $params['id'];
 250+ }
 251+ }
 252+
 253+ function getTableRow( $value ) {
 254+ $html = '';
 255+
 256+ $html .= Xml::tags( 'td', null,
 257+ Xml::tags( 'label', array( 'for' => $this->mID ), $this->getLabel() )
 258+ );
 259+ $html .= Xml::tags( 'td', array( 'class' => 'mw-input' ),
 260+ $this->getInputHTML( $value ) );
 261+
 262+ $html = Xml::tags( 'tr', null, $html ) . "\n";
 263+
 264+ return $html;
 265+ }
 266+
 267+ function getLabel() {
 268+ return $this->mLabel;
 269+ }
 270+
 271+ function getDefault() {
 272+ if ( isset( $this->mDefault ) ) {
 273+ return $this->mDefault;
 274+ } else {
 275+ return null;
 276+ }
 277+ }
 278+}
 279+
 280+class HTMLTextField extends HTMLFormField {
 281+
 282+ function getInputHTML( $value ) {
 283+ return Xml::input( $this->mName,
 284+ 45,
 285+ $value,
 286+ array( 'id' => $this->mID ) );
 287+ }
 288+
 289+}
 290+
 291+class HTMLCheckField extends HTMLFormField {
 292+ function getInputHTML( $value ) {
 293+ return Xml::check( $this->mName, $value, array( 'id' => $this->mID ) ) . '&nbsp;' .
 294+ Xml::tags( 'label', array( 'for' => $this->mID ), $this->mLabel );
 295+ }
 296+
 297+ function getLabel( ) {
 298+ return '&nbsp;'; // In the right-hand column.
 299+ }
 300+
 301+ function loadDataFromRequest( $request ) {
 302+ // GetCheck won't work like we want for checks.
 303+ if ($request->getCheck( 'wpEditToken' ) ) {
 304+ return $request->getBool( $this->mName );
 305+ } else {
 306+ return $this->getDefault();
 307+ }
 308+ }
 309+}
 310+
 311+class HTMLSelectField extends HTMLFormField {
 312+
 313+ function getInputHTML( $value ) {
 314+ $select = new XmlSelect( $this->mName, $this->mID, $value );
 315+
 316+ foreach( $this->mParams['options'] as $key => $label ) {
 317+ $select->addOption( $label, $key );
 318+ }
 319+
 320+ return $select->getHTML();
 321+ }
 322+}
 323+
 324+class HTMLMultiSelectField extends HTMLFormField {
 325+ function getInputHTML( $value ) {
 326+ $html = '';
 327+ foreach( $this->mParams['options'] as $key => $label ) {
 328+ $checkbox = Xml::check( $this->mName.'[]', in_array( $key, $value ),
 329+ array( 'id' => $this->mID, 'value' => $key ) );
 330+ $checkbox .= '&nbsp;' . Xml::tags( 'label', array( 'for' => $this->mID ), $label );
 331+
 332+ $html .= Xml::tags( 'p', null, $checkbox );
 333+ }
 334+
 335+ return $html;
 336+ }
 337+
 338+ function loadDataFromRequest( $request ) {
 339+ // won't work with getCheck
 340+ if ($request->getCheck( 'wpEditToken' ) ) {
 341+ return $request->getArray( $this->mName );
 342+ } else {
 343+ return $this->getDefault();
 344+ }
 345+ }
 346+}
 347+
 348+class HTMLRadioField extends HTMLFormField {
 349+ function getInputHTML( $value ) {
 350+ $html = '';
 351+
 352+ foreach( $this->mParams['options'] as $key => $label ) {
 353+ $html .= Xml::radio( $this->mName, $key, $key == $value,
 354+ array( 'id' => $this->mID."-$key" ) );
 355+ $html .= '&nbsp;' .
 356+ Xml::tags( 'label', array( 'for' => $this->mID."-$key" ), $label );
 357+ }
 358+
 359+ return $html;
 360+ }
 361+}
Index: branches/preferences-work/phase3/includes/AutoLoader.php
@@ -89,6 +89,7 @@
9090 'HTMLCacheUpdate' => 'includes/HTMLCacheUpdate.php',
9191 'HTMLCacheUpdateJob' => 'includes/HTMLCacheUpdate.php',
9292 'HTMLFileCache' => 'includes/HTMLFileCache.php',
 93+ 'HTMLForm' => 'includes/HTMLForm.php',
9394 'Http' => 'includes/HttpFunctions.php',
9495 'IEContentAnalyzer' => 'includes/IEContentAnalyzer.php',
9596 'ImageGallery' => 'includes/ImageGallery.php',

Status & tagging log