r56682 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r56681‎ | r56682 | r56683 >
Date:18:50, 20 September 2009
Author:happy-melon
Status:reverted
Tags:
Comment:
Document and tidy HTMLForm.php. :P
Modified paths:
  • /trunk/phase3/includes/HTMLForm.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/HTMLForm.php
@@ -1,16 +1,54 @@
22 <?php
33
 4+/**
 5+ * Object handling generic submission, CSRF protection, layout and
 6+ * other logic for UI forms. in a reusable manner.
 7+ *
 8+ * In order to generate the form, the HTMLForm object takes an array
 9+ * structure detailing the form fields available. Each element of the
 10+ * array is a basic property-list, including the type of field, the
 11+ * label it is to be given in the form, callbacks for validation and
 12+ * 'filtering', and other pertinent information.
 13+ *
 14+ * Field types are implemented as subclasses of the generic HTMLFormField
 15+ * object, and typically implement at least getInputHTML, which generates
 16+ * the HTML for the input field to be placed in the table.
 17+ *
 18+ * The constructor input is an associative array of $fieldname => $info,
 19+ * where $info is an Associative Array with any of the following:
 20+ *
 21+ * 'class' -- the subclass of HTMLFormField that will be used
 22+ * to create the object. *NOT* the CSS class!
 23+ * 'type' -- roughly translates into the <select> type attribute.
 24+ * if 'class' is not specified, this is used as a map
 25+ * through HTMLForm::$typeMappings to get the class name.
 26+ * 'default' -- default value when the form is displayed
 27+ * 'id' -- HTML id attribute
 28+ * 'options' -- varies according to the specific object.
 29+ * 'label-message' -- message key for a message to use as the label.
 30+ * can be an array of msg key and then parameters to
 31+ * the message.
 32+ * 'label' -- alternatively, a raw text message. Overridden by
 33+ * label-message
 34+ * 'help-message' -- message key for a message to use as a help text.
 35+ * can be an array of msg key and then parameters to
 36+ * the message.
 37+ * 'required' -- passed through to the object, indicating that it
 38+ * is a required field.
 39+ * 'size' -- the length of text fields
 40+ * 'filter-callback -- a function name to give you the chance to
 41+ * massage the inputted value before it's processed.
 42+ * @see HTMLForm::filter()
 43+ * 'validation-callback' -- a function name to give you the chance
 44+ * to impose extra validation on the field input.
 45+ * @see HTMLForm::validate()
 46+ *
 47+ * TODO: Document 'section' / 'subsection' stuff
 48+ */
449 class HTMLForm {
550 static $jsAdded = false;
651
7 - /* The descriptor is an array of arrays.
8 - i.e. array(
9 - 'fieldname' => array( 'section' => 'section/subsection',
10 - properties... ),
11 - ...
12 - )
13 - */
14 -
 52+ # A mapping of 'type' inputs onto standard HTMLFormField subclasses
1553 static $typeMappings = array(
1654 'text' => 'HTMLTextField',
1755 'select' => 'HTMLSelectField',
@@ -28,8 +66,25 @@
2967 'email' => 'HTMLTextField',
3068 'password' => 'HTMLTextField',
3169 );
 70+
 71+ protected $mMessagePrefix;
 72+ protected $mFlatFields;
 73+ protected $mFieldTree;
 74+ protected $mShowReset;
 75+ public $mFieldData;
 76+ protected $mSubmitCallback;
 77+ protected $mValidationErrorMessage;
 78+ protected $mIntro;
 79+ protected $mSubmitID;
 80+ protected $mSubmitText;
 81+ protected $mTitle;
3282
33 - function __construct( $descriptor, $messagePrefix ) {
 83+ /**
 84+ * Build a new HTMLForm from an array of field attributes
 85+ * @param $descriptor Array of Field constructs, as described above
 86+ * @param $messagePrefix String a prefix to go in front of default messages
 87+ */
 88+ public function __construct( $descriptor, $messagePrefix='' ) {
3489 $this->mMessagePrefix = $messagePrefix;
3590
3691 // Expand out into a tree.
@@ -43,7 +98,7 @@
4499
45100 $info['name'] = $fieldname;
46101
47 - $field = $this->loadInputFromParameters( $info );
 102+ $field = self::loadInputFromParameters( $info );
48103 $field->mParent = $this;
49104
50105 $setSection =& $loadedDescriptor;
@@ -70,6 +125,10 @@
71126 $this->mShowReset = true;
72127 }
73128
 129+ /**
 130+ * Add the HTMLForm-specific JavaScript, if it hasn't been
 131+ * done already.
 132+ */
74133 static function addJS() {
75134 if( self::$jsAdded ) return;
76135
@@ -78,6 +137,11 @@
79138 $wgOut->addScriptClass( 'htmlform' );
80139 }
81140
 141+ /**
 142+ * Initialise a new Object for the field
 143+ * @param $descriptor input Descriptor, as described above
 144+ * @return HTMLFormField subclass
 145+ */
82146 static function loadInputFromParameters( $descriptor ) {
83147 if ( isset( $descriptor['class'] ) ) {
84148 $class = $descriptor['class'];
@@ -95,15 +159,21 @@
96160 return $obj;
97161 }
98162
 163+ /**
 164+ * The here's-one-I-made-earlier option: do the submission if
 165+ * posted, or display the form with or without funky valiation
 166+ * errors
 167+ * @return Bool whether submission was successful.
 168+ */
99169 function show() {
100170 $html = '';
101171
102172 self::addJS();
103173
104 - // Load data from the request.
 174+ # Load data from the request.
105175 $this->loadData();
106176
107 - // Try a submission
 177+ # Try a submission
108178 global $wgUser, $wgRequest;
109179 $editToken = $wgRequest->getVal( 'wpEditToken' );
110180
@@ -114,23 +184,31 @@
115185 if( $result === true )
116186 return $result;
117187
118 - // Display form.
 188+ # Display form.
119189 $this->displayForm( $result );
 190+ return false;
120191 }
121192
122 - /** Return values:
123 - * TRUE == Successful submission
124 - * FALSE == No submission attempted
125 - * Anything else == Error to display.
126 - */
 193+ /**
 194+ * Validate all the fields, and call the submision callback
 195+ * function if everything is kosher.
 196+ * @return Mixed Bool true == Successful submission, Bool false
 197+ * == No submission attempted, anything else == Error to
 198+ * display.
 199+ */
127200 function trySubmit() {
128 - // Check for validation
 201+ # Check for validation
129202 foreach( $this->mFlatFields as $fieldname => $field ) {
130 - if ( !empty( $field->mParams['nodata'] ) ) continue;
131 - if ( $field->validate( $this->mFieldData[$fieldname],
132 - $this->mFieldData ) !== true ) {
133 - return isset( $this->mValidationErrorMessage ) ?
134 - $this->mValidationErrorMessage : array( 'htmlform-invalid-input' );
 203+ if ( !empty( $field->mParams['nodata'] ) )
 204+ continue;
 205+ if ( $field->validate(
 206+ $this->mFieldData[$fieldname],
 207+ $this->mFieldData )
 208+ !== true )
 209+ {
 210+ return isset( $this->mValidationErrorMessage )
 211+ ? $this->mValidationErrorMessage
 212+ : array( 'htmlform-invalid-input' );
135213 }
136214 }
137215
@@ -143,18 +221,40 @@
144222 return $res;
145223 }
146224
 225+ /**
 226+ * Set a callback to a function to do something with the form
 227+ * once it's been successfully validated.
 228+ * @param $cb String function name. The function will be passed
 229+ * the output from HTMLForm::filterDataForSubmit, and must
 230+ * return Bool true on success, Bool false if no submission
 231+ * was attempted, or String HTML output to display on error.
 232+ */
147233 function setSubmitCallback( $cb ) {
148234 $this->mSubmitCallback = $cb;
149235 }
150236
 237+ /**
 238+ * Set a message to display on a validation error.
 239+ * @param $msg Mixed String or Array of valid inputs to wfMsgExt()
 240+ * (so each entry can be either a String or Array)
 241+ */
151242 function setValidationErrorMessage( $msg ) {
152243 $this->mValidationErrorMessage = $msg;
153244 }
154245
 246+ /**
 247+ * Set the introductory message
 248+ * @param $msg String complete text of message to display
 249+ */
155250 function setIntro( $msg ) {
156251 $this->mIntro = $msg;
157252 }
158253
 254+ /**
 255+ * Display the form (sending to wgOut), with an appropriate error
 256+ * message or stack of messages, and any validation errors, etc.
 257+ * @param $submitResult Mixed output from HTMLForm::trySubmit()
 258+ */
159259 function displayForm( $submitResult ) {
160260 global $wgOut;
161261
@@ -179,6 +279,11 @@
180280 $wgOut->addHTML( $html );
181281 }
182282
 283+ /**
 284+ * Wrap the form innards in an actual <form> element
 285+ * @param $html String HTML contents to wrap.
 286+ * @return String wrapped HTML.
 287+ */
183288 function wrapForm( $html ) {
184289 return Html::rawElement(
185290 'form',
@@ -190,6 +295,10 @@
191296 );
192297 }
193298
 299+ /**
 300+ * Get the hidden fields that should go inside the form.
 301+ * @return String HTML.
 302+ */
194303 function getHiddenFields() {
195304 global $wgUser;
196305 $html = '';
@@ -200,6 +309,10 @@
201310 return $html;
202311 }
203312
 313+ /**
 314+ * Get the submit and (potentially) reset buttons.
 315+ * @return String HTML.
 316+ */
204317 function getButtons() {
205318 $html = '';
206319
@@ -225,10 +338,17 @@
226339 return $html;
227340 }
228341
 342+ /**
 343+ * Get the whole body of the form.
 344+ */
229345 function getBody() {
230346 return $this->displaySection( $this->mFieldTree );
231347 }
232348
 349+ /**
 350+ * Format and display an error message stack.
 351+ * @param $errors Mixed String or Array of message keys
 352+ */
233353 function displayErrors( $errors ) {
234354 if ( is_array( $errors ) ) {
235355 $errorstr = $this->formatErrors( $errors );
@@ -242,6 +362,11 @@
243363 $wgOut->addHTML( $errorstr );
244364 }
245365
 366+ /**
 367+ * Format a stack of error messages into a single HTML string
 368+ * @param $errors Array of message keys/values
 369+ * @return String HTML, a <ul> list of errors
 370+ */
246371 static function formatErrors( $errors ) {
247372 $errorstr = '';
248373 foreach ( $errors as $error ) {
@@ -263,30 +388,62 @@
264389 return $errorstr;
265390 }
266391
 392+ /**
 393+ * Set the text for the submit button
 394+ * @param $t String plaintext.
 395+ */
267396 function setSubmitText( $t ) {
268397 $this->mSubmitText = $t;
269398 }
270399
 400+ /**
 401+ * Get the text for the submit button, either customised or a default.
 402+ * @return unknown_type
 403+ */
271404 function getSubmitText() {
272 - return isset( $this->mSubmitText ) ? $this->mSubmitText : wfMsg( 'htmlform-submit' );
 405+ return $this->mSubmitText
 406+ ? $this->mSubmitText
 407+ : wfMsg( 'htmlform-submit' );
273408 }
274409
 410+ /**
 411+ * Set the id for the submit button.
 412+ * @param $t String. FIXME: Integrity is *not* validated
 413+ */
275414 function setSubmitID( $t ) {
276415 $this->mSubmitID = $t;
277416 }
278417
 418+ /**
 419+ * Set the prefix for various default messages
 420+ * TODO: currently only used for the <fieldset> legend on forms
 421+ * with multiple sections; should be used elsewhre?
 422+ * @param $p String
 423+ */
279424 function setMessagePrefix( $p ) {
280425 $this->mMessagePrefix = $p;
281426 }
282427
 428+ /**
 429+ * Set the title for form submission
 430+ * @param $t Title of page the form is on/should be posted to
 431+ */
283432 function setTitle( $t ) {
284433 $this->mTitle = $t;
285434 }
286435
 436+ /**
 437+ * Get the title
 438+ * @return Title
 439+ */
287440 function getTitle() {
288441 return $this->mTitle;
289442 }
290443
 444+ /**
 445+ * TODO: Document
 446+ * @param $fields
 447+ */
291448 function displaySection( $fields ) {
292449 $tableHtml = '';
293450 $subsectionHtml = '';
@@ -295,8 +452,8 @@
296453 foreach( $fields as $key => $value ) {
297454 if ( is_object( $value ) ) {
298455 $v = empty( $value->mParams['nodata'] )
299 - ? $this->mFieldData[$key]
300 - : $value->getDefault();
 456+ ? $this->mFieldData[$key]
 457+ : $value->getDefault();
301458 $tableHtml .= $value->getTableRow( $v );
302459
303460 if( $value->getLabel() != '&nbsp;' )
@@ -319,6 +476,9 @@
320477 return $subsectionHtml . "\n" . $tableHtml;
321478 }
322479
 480+ /**
 481+ * Construct the form fields from the Descriptor array
 482+ */
323483 function loadData() {
324484 global $wgRequest;
325485
@@ -333,7 +493,7 @@
334494 }
335495 }
336496
337 - // Filter data.
 497+ # Filter data.
338498 foreach( $fieldData as $name => &$value ) {
339499 $field = $this->mFlatFields[$name];
340500 $value = $field->filter( $value, $this->mFlatFields );
@@ -342,33 +502,60 @@
343503 $this->mFieldData = $fieldData;
344504 }
345505
346 - function importData( $fieldData ) {
347 - // Filter data.
348 - foreach( $fieldData as $name => &$value ) {
349 - $field = $this->mFlatFields[$name];
350 - $value = $field->filter( $value, $this->mFlatFields );
351 - }
352 -
353 - foreach( $this->mFlatFields as $fieldname => $field ) {
354 - if ( !isset( $fieldData[$fieldname] ) )
355 - $fieldData[$fieldname] = $field->getDefault();
356 - }
357 -
358 - $this->mFieldData = $fieldData;
359 - }
360 -
 506+ /**
 507+ * Stop a reset button being shown for this form
 508+ * @param $suppressReset Bool set to false to re-enable the
 509+ * button again
 510+ */
361511 function suppressReset( $suppressReset = true ) {
362512 $this->mShowReset = !$suppressReset;
363513 }
364514
 515+ /**
 516+ * Overload this if you want to apply special filtration routines
 517+ * to the form as a whole, after it's submitted but before it's
 518+ * processed.
 519+ * @param $data
 520+ * @return unknown_type
 521+ */
365522 function filterDataForSubmit( $data ) {
366523 return $data;
367524 }
368525 }
369526
 527+/**
 528+ * The parent class to generate form fields. Any field type should
 529+ * be a subclass of this.
 530+ */
370531 abstract class HTMLFormField {
 532+
 533+ protected $mValidationCallback;
 534+ protected $mFilterCallback;
 535+ protected $mName;
 536+ public $mParams;
 537+ protected $mLabel; # String label. Set on construction
 538+ protected $mID;
 539+ protected $mDefault;
 540+ public $mParent;
 541+
 542+ /**
 543+ * This function must be implemented to return the HTML to generate
 544+ * the input object itself. It should not implement the surrounding
 545+ * table cells/rows, or labels/help messages.
 546+ * @param $value String the value to set the input to; eg a default
 547+ * text for a text input.
 548+ * @return String valid HTML.
 549+ */
371550 abstract function getInputHTML( $value );
372551
 552+ /**
 553+ * Override this function to add specific validation checks on the
 554+ * field input. Don't forget to call parent::validate() to ensure
 555+ * that the user-defined callback mValidationCallback is still run
 556+ * @param $value String the value the field was submitted with
 557+ * @param $alldata $all the data collected from the form
 558+ * @return Bool is the input valid
 559+ */
373560 function validate( $value, $alldata ) {
374561 if ( isset( $this->mValidationCallback ) ) {
375562 return call_user_func( $this->mValidationCallback, $value, $alldata );
@@ -395,6 +582,12 @@
396583 return true;
397584 }
398585
 586+ /**
 587+ * Get the value that this input has been set to from a posted form,
 588+ * or the input's default value if it has not been set.
 589+ * @param $request WebRequest
 590+ * @return String the value
 591+ */
399592 function loadDataFromRequest( $request ) {
400593 if( $request->getCheck( $this->mName ) ) {
401594 return $request->getText( $this->mName );
@@ -403,9 +596,14 @@
404597 }
405598 }
406599
 600+ /**
 601+ * Initialise the object
 602+ * @param $params Associative Array. See HTMLForm doc for syntax.
 603+ */
407604 function __construct( $params ) {
408605 $this->mParams = $params;
409606
 607+ # Generate the label from a message, if possible
410608 if( isset( $params['label-message'] ) ) {
411609 $msgInfo = $params['label-message'];
412610
@@ -453,8 +651,14 @@
454652 }
455653 }
456654
 655+ /**
 656+ * Get the complete table row for the input, including help text,
 657+ * labels, and whatever.
 658+ * @param $value String the value to set the input to.
 659+ * @return String complete HTML table row.
 660+ */
457661 function getTableRow( $value ) {
458 - // Check for invalid data.
 662+ # Check for invalid data.
459663 global $wgRequest;
460664
461665 $errors = $this->validate( $value, $this->mParent->mFieldData );
@@ -517,7 +721,14 @@
518722 }
519723 }
520724
521 - static function flattenOptions( $options ) {
 725+ /**
 726+ * flatten an array of options to a single array, for instance,
 727+ * a set of <options> inside <optgroups>.
 728+ * @param $options Associative Array with values either Strings
 729+ * or Arrays
 730+ * @return Array flattened input
 731+ */
 732+ public static function flattenOptions( $options ) {
522733 $flatOpts = array();
523734
524735 foreach( $options as $key => $value ) {
@@ -533,11 +744,11 @@
534745 }
535746
536747 class HTMLTextField extends HTMLFormField {
537 - # Override in derived classes to use other Xml::... functions
538 - protected $mFunction = 'input';
539748
540749 function getSize() {
541 - return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 45;
 750+ return isset( $this->mParams['size'] )
 751+ ? $this->mParams['size']
 752+ : 45;
542753 }
543754
544755 function getInputHTML( $value ) {
@@ -572,21 +783,25 @@
573784 $attribs[$param] = '';
574785 }
575786 }
 787+
 788+ # Implement tiny differences between some field variants
 789+ # here, rather than creating a new class for each one which
 790+ # is essentially just a clone of this one.
576791 if ( isset( $this->mParams['type'] ) ) {
577792 switch ( $this->mParams['type'] ) {
578 - case 'email':
579 - $attribs['type'] = 'email';
580 - break;
581 - case 'int':
582 - $attribs['type'] = 'number';
583 - break;
584 - case 'float':
585 - $attribs['type'] = 'number';
586 - $attribs['step'] = 'any';
587 - break;
588 - case 'password':
589 - $attribs['type'] = 'password';
590 - break;
 793+ case 'email':
 794+ $attribs['type'] = 'email';
 795+ break;
 796+ case 'int':
 797+ $attribs['type'] = 'number';
 798+ break;
 799+ case 'float':
 800+ $attribs['type'] = 'number';
 801+ $attribs['step'] = 'any';
 802+ break;
 803+ case 'password':
 804+ $attribs['type'] = 'password';
 805+ break;
591806 }
592807 }
593808 }
@@ -595,9 +810,15 @@
596811 }
597812 }
598813
 814+/**
 815+ * A field that will contain a numeric value
 816+ */
599817 class HTMLFloatField extends HTMLTextField {
 818+
600819 function getSize() {
601 - return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 20;
 820+ return isset( $this->mParams['size'] )
 821+ ? $this->mParams['size']
 822+ : 20;
602823 }
603824
604825 function validate( $value, $alldata ) {
@@ -611,8 +832,8 @@
612833
613834 $in_range = true;
614835
615 - # The "int" part of these message names is rather confusing. They make
616 - # equal sense for all numbers.
 836+ # The "int" part of these message names is rather confusing.
 837+ # They make equal sense for all numbers.
617838 if ( isset( $this->mParams['min'] ) ) {
618839 $min = $this->mParams['min'];
619840 if ( $min > $value )
@@ -629,6 +850,9 @@
630851 }
631852 }
632853
 854+/**
 855+ * A field that must contain a number
 856+ */
633857 class HTMLIntField extends HTMLFloatField {
634858 function validate( $value, $alldata ) {
635859 $p = parent::validate( $value, $alldata );
@@ -643,6 +867,9 @@
644868 }
645869 }
646870
 871+/**
 872+ * A checkbox field
 873+ */
647874 class HTMLCheckField extends HTMLFormField {
648875 function getInputHTML( $value ) {
649876 if ( !empty( $this->mParams['invert'] ) )
@@ -657,8 +884,12 @@
658885 Html::rawElement( 'label', array( 'for' => $this->mID ), $this->mLabel );
659886 }
660887
 888+ /**
 889+ * For a checkbox, the label goes on the right hand side, and is
 890+ * added in getInputHTML(), rather than HTMLFormField::getRow()
 891+ */
661892 function getLabel() {
662 - return '&nbsp;'; // In the right-hand column.
 893+ return '&nbsp;';
663894 }
664895
665896 function loadDataFromRequest( $request ) {
@@ -682,6 +913,9 @@
683914 }
684915 }
685916
 917+/**
 918+ * A select dropdown field. Basically a wrapper for Xmlselect class
 919+ */
686920 class HTMLSelectField extends HTMLFormField {
687921
688922 function validate( $value, $alldata ) {
@@ -698,9 +932,9 @@
699933 function getInputHTML( $value ) {
700934 $select = new XmlSelect( $this->mName, $this->mID, strval( $value ) );
701935
702 - // If one of the options' 'name' is int(0), it is automatically selected.
703 - // because PHP sucks and things int(0) == 'some string'.
704 - // Working around this by forcing all of them to strings.
 936+ # If one of the options' 'name' is int(0), it is automatically selected.
 937+ # because PHP sucks and things int(0) == 'some string'.
 938+ # Working around this by forcing all of them to strings.
705939 $options = array_map( 'strval', $this->mParams['options'] );
706940
707941 if( !empty( $this->mParams['disabled'] ) ) {
@@ -713,6 +947,9 @@
714948 }
715949 }
716950
 951+/**
 952+ * Select dropdown field, with an additional "other" textbox.
 953+ */
717954 class HTMLSelectOrOtherField extends HTMLTextField {
718955 static $jsAdded = false;
719956
@@ -783,15 +1020,19 @@
7841021 }
7851022 }
7861023
 1024+/**
 1025+ * Multi-select field
 1026+ */
7871027 class HTMLMultiSelectField extends HTMLFormField {
 1028+
7881029 function validate( $value, $alldata ) {
7891030 $p = parent::validate( $value, $alldata );
7901031 if( $p !== true ) return $p;
7911032
7921033 if( !is_array( $value ) ) return false;
7931034
794 - // If all options are valid, array_intersect of the valid options and the provided
795 - // options will return the provided options.
 1035+ # If all options are valid, array_intersect of the valid options
 1036+ # and the provided options will return the provided options.
7961037 $validOptions = HTMLFormField::flattenOptions( $this->mParams['options'] );
7971038
7981039 $validValues = array_intersect( $value, $validOptions );
@@ -834,7 +1075,7 @@
8351076 }
8361077
8371078 function loadDataFromRequest( $request ) {
838 - // won't work with getCheck
 1079+ # won't work with getCheck
8391080 if( $request->getCheck( 'wpEditToken' ) ) {
8401081 $arr = $request->getArray( $this->mName );
8411082
@@ -860,6 +1101,9 @@
8611102 }
8621103 }
8631104
 1105+/**
 1106+ * Radio checkbox fields.
 1107+ */
8641108 class HTMLRadioField extends HTMLFormField {
8651109 function validate( $value, $alldata ) {
8661110 $p = parent::validate( $value, $alldata );
@@ -876,6 +1120,10 @@
8771121 return wfMsgExt( 'htmlform-select-badoption', 'parseinline' );
8781122 }
8791123
 1124+ /**
 1125+ * This returns a block of all the radio options, in one cell.
 1126+ * @see includes/HTMLFormField#getInputHTML()
 1127+ */
8801128 function getInputHTML( $value ) {
8811129 $html = $this->formatOptions( $this->mParams['options'], $value );
8821130
@@ -890,6 +1138,7 @@
8911139 $attribs['disabled'] = 'disabled';
8921140 }
8931141
 1142+ # TODO: should this produce an unordered list perhaps?
8941143 foreach( $options as $label => $info ) {
8951144 if( is_array( $info ) ) {
8961145 $html .= Html::rawElement( 'h1', array(), $label ) . "\n";
@@ -913,6 +1162,9 @@
9141163 }
9151164 }
9161165
 1166+/**
 1167+ * An information field (text blob), not a proper input.
 1168+ */
9171169 class HTMLInfoField extends HTMLFormField {
9181170 function __construct( $info ) {
9191171 $info['nodata'] = true;

Follow-up revisions

RevisionCommit summaryAuthorDate
r56937Revert broken rewrite of login system; totally broken....brion00:49, 26 September 2009
r57024Recommit some of the 'backend' stuff from the Login branch, after talking wit...happy-melon19:04, 28 September 2009

Status & tagging log