r96581 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r96580‎ | r96581 | r96582 >
Date:16:22, 8 September 2011
Author:yaron
Status:deferred (Comments)
Tags:
Comment:
Added (slightly modified) patch from LY Meng to allow multiple-instance templates to be embedded within another template call
Modified paths:
  • /trunk/extensions/SemanticForms/includes/SF_FormPrinter.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticForms/includes/SF_FormPrinter.php
@@ -8,6 +8,7 @@
99 * @author Harold Solbrig
1010 * @author Daniel Hansch
1111 * @author Stephan Gambke
 12+ * @author LY Meng
1213 * @file
1314 * @ingroup SF
1415 */
@@ -218,6 +219,18 @@
219220 }
220221 }
221222
 223+ static function placeholderFormat( $templateName, $fieldName ) {
 224+ return $templateName . '___' . $fieldName;
 225+ }
 226+
 227+ static function makePlaceholderInWikiText( $str ) {
 228+ return '@replace_' . $str . '@';
 229+ }
 230+
 231+ static function makePlaceholderInFormHTML( $str ) {
 232+ return '@insertHTML_' . $str . '@';
 233+ }
 234+
222235 /**
223236 * Creates the HTML for the inner table for every instance of a
224237 * multiple-instance template in the form.
@@ -248,6 +261,53 @@
249262 }
250263
251264 /**
 265+ * Creates the HTML for a single instance of a multiple-instance template;
 266+ * plus the end tags for the full multiple-instance HTML.
 267+ */
 268+ function multipleTemplateInstanceHTML( $all_instances_printed, &$section, $instance_num, $add_button_text ) {
 269+ global $sfgTabIndex;
 270+
 271+ if ( ! $all_instances_printed ) {
 272+ // Add the character "a" onto the instance number of this input
 273+ // in the form, to differentiate the inputs the form starts out
 274+ // with from any inputs added by the Javascript.
 275+ $section = str_replace( '[num]', "[{$instance_num}a]", $section );
 276+ // @TODO - this replacement should be
 277+ // case- and spacing-insensitive
 278+ $section = str_replace( ' id=', ' origID=', $section );
 279+ $text = "\t\t" . Xml::tags( 'div',
 280+ array(
 281+ // The "multipleTemplate" class is there for
 282+ // backwards-compatibility with any custom CSS on people's
 283+ // wikis before SF 2.0.9.
 284+ 'class' => "multipleTemplateInstance multipleTemplate"
 285+ ),
 286+ $this->multipleTemplateInstanceTableHTML( $section )
 287+ ) . "\n";
 288+
 289+ } else { //if ( $all_instances_printed ) {
 290+ // This is the last instance of this
 291+ // template - print all the sections
 292+ // necessary for adding additional
 293+ // instances.
 294+ $text = "\t\t" . Xml::tags( 'div',
 295+ array(
 296+ 'class' => "multipleTemplateStarter",
 297+ 'style' => "display: none",
 298+ ),
 299+ $this->multipleTemplateInstanceTableHTML( $section )
 300+ ) . "\n";
 301+ $text .= <<<END
 302+ </div><!-- multipleTemplateList -->
 303+ <p style="margin-left:10px;" />
 304+ <p><input type="button" value="$add_button_text" tabindex="$sfgTabIndex" class="multipleTemplateAdder" /></p>
 305+ </div><!-- multipleTemplateWrapper -->
 306+END;
 307+ }
 308+ return $text;
 309+ }
 310+
 311+ /**
252312 * This function is the real heart of the entire Semantic Forms
253313 * extension. It handles two main actions: (1) displaying a form on the
254314 * screen, given a form definition and possibly page contents (if an
@@ -257,7 +317,7 @@
258318 * It also does some related tasks, like figuring out the page name (if
259319 * only a page formula exists).
260320 */
261 - function formHTML( $form_def, $form_submitted, $source_is_page, $form_id = null, $existing_page_content = null, $page_name = null, $page_name_formula = null, $is_query = false, $embedded = false ) {
 321+ function formHTML( $form_def, $form_submitted, $source_is_page, $form_id = null, $existing_page_content = null, $page_name = null, $page_name_formula = null, $is_query = false, $is_embedded = false ) {
262322 global $wgRequest, $wgUser, $wgOut, $wgParser;
263323 global $sfgTabIndex; // used to represent the current tab index in the form
264324 global $sfgFieldNum; // used for setting various HTML IDs
@@ -292,10 +352,10 @@
293353 $original_page_content = $existing_page_content;
294354 } else {
295355 $original_page_content = null;
296 - if ( $wgRequest->getCheck( 'free_text' ) ) {
297 - $existing_page_content = $wgRequest->getVal( 'free_text' );
298 - $form_is_partial = true;
299 - }
 356+ if ( $wgRequest->getCheck( 'free_text' ) ) {
 357+ $existing_page_content = $wgRequest->getVal( 'free_text' );
 358+ $form_is_partial = true;
 359+ }
300360 }
301361
302362 // Disable all form elements if user doesn't have edit
@@ -303,7 +363,7 @@
304364 // editing permissions can be set in different ways.
305365 // HACK - sometimes we don't know the page name in advance, but
306366 // we still need to set a title here for testing permissions.
307 - if ( $embedded ) {
 367+ if ( $is_embedded ) {
308368 // If this is an embedded form (probably a 'RunQuery'),
309369 // just use the name of the actual page we're on.
310370 global $wgTitle;
@@ -419,6 +479,14 @@
420480 $instance_num = 0;
421481 $all_instances_printed = false;
422482 $strict_parsing = false;
 483+
 484+ // Placeholder name in the form
 485+ $curPlaceholder = null;
 486+ // Used to store the HTML code of the multiple template, to reinsert it into the right spot
 487+ $multipleTemplateString = "";
 488+ // This array will keep track of all the replaced @<name>@ strings
 489+ $placeholderFields = array();
 490+
423491 for ( $section_num = 0; $section_num < count( $form_def_sections ); $section_num++ ) {
424492 $start_position = 0;
425493 $template_text = "";
@@ -426,6 +494,9 @@
427495 // array doesn't get modified; is it necessary?
428496 $section = " " . $form_def_sections[$section_num];
429497
 498+
 499+ $multipleTemplateString="";
 500+
430501 while ( $brackets_loc = strpos( $section, '{{{', $start_position ) ) {
431502 $brackets_end_loc = strpos( $section, "}}}", $brackets_loc );
432503 $bracketed_string = substr( $section, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) );
@@ -454,29 +525,47 @@
455526 $template_label = $sub_components[1];
456527 } elseif ( $sub_components[0] == 'add button text' ) {
457528 $add_button_text = $sub_components[1];
 529+ } elseif ($sub_components[0] == 'embed in field') {
 530+ // Placeholder on form template level. Assume that the template form def
 531+ // will have a multiple+placeholder parameters, and get the placeholder value.
 532+ // We expect something like TemplateName[fieldName], and convert it to the
 533+ // TemplateName___fieldName form used internally.
 534+ preg_match( '/\s*(.*)\[(.*)\]\s*/', $sub_components[1], $matches );
 535+ $curPlaceholder = ( count( $matches ) > 2 ) ? self::placeholderFormat( $matches[1], $matches[2] ) : null;
 536+ unset ($matches);
458537 }
459538 }
460539 }
461 - // If this is the first instance, add the label into the form, if
462 - // there is one, and add the appropriate wrapper div, if this is
463 - // a multiple-instance template.
 540+ // If this is the first instance, add
 541+ // the label into the form, if there is
 542+ // one, and add the appropriate wrapper
 543+ // div, if this is a multiple-instance
 544+ // template.
464545 if ( $old_template_name != $template_name ) {
465546 if ( isset( $template_label ) ) {
466547 $form_text .= "<fieldset>\n";
467548 $form_text .= "<legend>$template_label</legend>\n";
468549 }
469 - if ($allow_multiple) {
470 - $form_text .= "\t" . '<div class="multipleTemplateWrapper">' . "\n";
471 - $form_text .= "\t" . '<div class="multipleTemplateList">' . "\n";
472 - }
 550+ // If $curPlaceholder is set, it means we want to insert a
 551+ // multiple template form's HTML into the main form's HTML.
 552+ // So, the HTML will be stored in $multipleTemplateString.
 553+ if ($allow_multiple) {
 554+ $multipleTemplateString .= "\t" . '<div class="multipleTemplateWrapper">' . "\n";
 555+ $multipleTemplateString .= "\t" . '<div class="multipleTemplateList">' . "\n";
 556+ if ( $curPlaceholder == null ) {
 557+ $form_text .= $multipleTemplateString;
 558+ }
 559+ }
473560 }
474561 $template_text .= "{{" . $template_name;
475562 $all_fields = $tif->getAllFields();
476563 // remove template tag
477564 $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
478565 $template_instance_query_values = $wgRequest->getArray( $query_template_name );
479 - // If we are editing a page, and this template can be found more than
480 - // once in that page, and multiple values are allowed, repeat this
 566+ // If we are editing a page, and this
 567+ // template can be found more than
 568+ // once in that page, and multiple
 569+ // values are allowed, repeat this
481570 // section.
482571 $existing_template_text = null;
483572 if ( $source_is_page || $form_is_partial ) {
@@ -639,7 +728,7 @@
640729 $instance_num = 0;
641730 // =====================================================
642731 // field processing
643 - // =====================================================
 732+ // =====================================================
644733 } elseif ( $tag_title == 'field' ) {
645734 $field_name = trim( $tag_components[1] );
646735 // cycle through the other components
@@ -656,6 +745,7 @@
657746 $possible_values = null;
658747 $semantic_property = null;
659748 $preload_page = null;
 749+ $holds_template = false;
660750 for ( $i = 2; $i < count( $tag_components ); $i++ ) {
661751 $component = trim( $tag_components[$i] );
662752 if ( $component == 'mandatory' ) {
@@ -681,6 +771,12 @@
682772 if ( count( $sub_components ) == 1 ) {
683773 // add handling for single-value params, for custom input types
684774 $field_args[$sub_components[0]] = null;
 775+
 776+ if ( $component == 'holds template' ) {
 777+ $is_hidden = true;
 778+ $holds_template = true;
 779+ $placeholderFields[] = self::placeholderFormat( $template_name, $field_name );
 780+ }
685781 } elseif ( count( $sub_components ) == 2 ) {
686782 // First, set each value as its own entry in $field_args.
687783 $field_args[$sub_components[0]] = $sub_components[1];
@@ -767,10 +863,11 @@
768864 $field_args['default filename'] = $default_filename;
769865 } elseif ( $sub_components[0] == 'restricted' ) {
770866 $is_restricted = !array_intersect(
771 - $wgUser->getEffectiveGroups(),
772 - array_map( 'trim', explode( ',', $sub_components[1] ) )
 867+ $wgUser->getEffectiveGroups(),
 868+ array_map( 'trim', explode( ',', $sub_components[1] ) )
773869 );
774870 }
 871+
775872 }
776873 }
777874 } // end for
@@ -824,15 +921,28 @@
825922 }
826923 }
827924
828 - // if the user is editing a page, and that page contains a call to
 925+ // If the user is editing a page, and that page contains a call to
829926 // the template being processed, get the current field's value
830927 // from the template call
831928 if ( $source_is_page && ( ! empty( $existing_template_text ) ) ) {
832929 if ( isset( $template_contents[$field_name] ) ) {
833930 $cur_value = $template_contents[$field_name];
834 - // now remove this value from $template_contents, so that
835 - // at the end we can have a list of all the fields that
836 - // weren't handled by the form
 931+
 932+ // If the field is a placeholder, the contents of this template
 933+ // parameter should be treated as elements parsed by an another
 934+ // multiple template form.
 935+ // By putting that at the very end of the parsed string, we'll
 936+ // have it processed as a regular multiple template form.
 937+ if ( $holds_template ) {
 938+ $existing_page_content = $existing_page_content . $cur_value;
 939+ }
 940+
 941+ // Now remove this value
 942+ // from $template_contents,
 943+ // so that at the end we
 944+ // can have a list of all
 945+ // the fields that weren't
 946+ // handled by the form.
837947 unset( $template_contents[$field_name] );
838948 } else {
839949 $cur_value = '';
@@ -1030,9 +1140,9 @@
10311141 }
10321142 // increment the global field number regardless
10331143 $sfgFieldNum++;
1034 - // if the field is a date field, and its default value was set
 1144+ // If the field is a date field, and its default value was set
10351145 // to 'now', and it has no current value, set $cur_value to be
1036 - // the current date
 1146+ // the current date.
10371147 if ( $default_value == 'now' &&
10381148 // if the date is hidden, cur_value will already be set
10391149 // to the default value
@@ -1082,9 +1192,9 @@
10831193 }
10841194 }
10851195 }
1086 - // if the field is a text field, and its default value was set
 1196+ // If the field is a text field, and its default value was set
10871197 // to 'current user', and it has no current value, set $cur_value
1088 - // to be the current user
 1198+ // to be the current user.
10891199 if ( $default_value == 'current user' &&
10901200 // if the date is hidden, cur_value will already be set
10911201 // to the default value
@@ -1094,11 +1204,26 @@
10951205 $cur_value = $cur_value_in_template;
10961206 }
10971207 }
 1208+
 1209+ // Generate a hidden field with a placeholder value that will be replaced
 1210+ // by the multiple-instances template output at form submission.
 1211+ ////<input type="hidden" value="@replace_Town___mayors@" name="Town[town_mayors]" />
 1212+ if ( $holds_template ) {
 1213+ $cur_value = self::makePlaceholderInWikiText( self::placeholderFormat($template_name,$field_name) );
 1214+ }
 1215+
10981216 $new_text = $this->formFieldHTML( $form_field, $cur_value );
10991217
1100 - // if this field is disabled, add a hidden field holding
 1218+ // Add a field just after the hidden field, within the HTML, to locate
 1219+ // where the multiple-templates HTML, stored in $multipleTemplateString,
 1220+ // should be inserted.
 1221+ if ( $holds_template ) {
 1222+ $new_text .= self::makePlaceholderInFormHTML( self::placeholderFormat( $template_name, $field_name ) );
 1223+ }
 1224+
 1225+ // If this field is disabled, add a hidden field holding
11011226 // the value of this field, because disabled inputs for some
1102 - // reason don't submit their value
 1227+ // reason don't submit their value.
11031228 if ( $form_field->isDisabled() ) {
11041229 if ( $field_name == 'free text' || $field_name == '<freetext>' ) {
11051230 $new_text .= SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' );
@@ -1247,8 +1372,26 @@
12481373 $template_text .= SFFormUtils::addUnhandledFields( $template_name );
12491374 }
12501375 $template_text .= "}}";
1251 - $data_text .= $template_text . "\n";
1252 - // If there is a placeholder in the text, we know that we are
 1376+
 1377+
 1378+
 1379+ /*used on submission on the template form level
 1380+ 1. the base $template_text will contain strings like "@replace_xxx@" in the hidden fields when the form will be submitted
 1381+ on the following loops, the text for the multiple form templates is progressively reinserted in the main data, always keeping a trailing @replace_xxx@ for a given field
 1382+ the trailing @replace_xxx@ will be deleted at the end with the data from
 1383+
 1384+ note: this clean up step could also be done with a regexp instead of keeping a track array /@replace_(.*)@/
 1385+ */
 1386+
 1387+ $reptmp = self::makePlaceholderInWikiText( $curPlaceholder );
 1388+ if ( $curPlaceholder != null && $data_text && strpos( $data_text, $reptmp, 0 ) !== false) {
 1389+ $data_text = preg_replace( '/' . $reptmp . '/', $template_text . $reptmp, $data_text );
 1390+ } else {
 1391+ $data_text .= $template_text . "\n";
 1392+ }
 1393+
 1394+ // If there is a placeholder in the
 1395+ // text, we know that we are
12531396 // doing a replace.
12541397 if ( $existing_page_content && strpos( $existing_page_content, '{{{insertionpoint}}}', 0 ) !== false ) {
12551398 $existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}(\r?\n?)/',
@@ -1267,53 +1410,45 @@
12681411 }
12691412
12701413 if ( $allow_multiple ) {
 1414+ if ( $curPlaceholder == null ) {
 1415+ // The normal process.
 1416+ $form_text .= $this->multipleTemplateInstanceHTML( $all_instances_printed, $section, $instance_num, $add_button_text );
 1417+ } else { // if ( $curPlaceholder != null ){
 1418+ // The template text won't be appended at the end of the template like for usual multiple template forms.
 1419+ // The HTML text will then be stored in the $multipleTemplateString variable,
 1420+ // and then added in the right @insertHTML_".$placeHolderField."@"; position
 1421+ // Optimization: actually, instead of separating the processes, the usual multiple
 1422+ // template forms could also be handled this way if a fitting placeholder tag was added.
 1423+ $multipleTemplateString .= $this->multipleTemplateInstanceHTML( $all_instances_printed, $section, $instance_num, $add_button_text );
 1424+ // We replace the $multipleTemplateString HTML into the
 1425+ // current placeholder tag, but also add another
 1426+ // placeholder tag, to keep track of it.
 1427+ $multipleTemplateString .= self::makePlaceholderInFormHTML( $curPlaceholder );
 1428+ $form_text = preg_replace( '/' . self::makePlaceholderInFormHTML( $curPlaceholder ) . '/',
 1429+ $multipleTemplateString, $form_text );
 1430+ }
12711431 if ( ! $all_instances_printed ) {
1272 - // Add the character "a" onto the instance number of this input
1273 - // in the form, to differentiate the inputs the form starts out
1274 - // with from any inputs added by the Javascript.
1275 - $section = str_replace( '[num]', "[{$instance_num}a]", $section );
1276 - // @TODO - this replacement should be
1277 - // case- and spacing-insensitive
1278 - $section = str_replace( ' id=', ' origID=', $section );
1279 - $form_text .= "\t\t" . Xml::tags( 'div',
1280 - array(
1281 - // The "multipleTemplate" class is there for
1282 - // backwards-compatibility with any custom CSS on people's
1283 - // wikis before SF 2.0.9.
1284 - 'class' => "multipleTemplateInstance multipleTemplate"
1285 - ),
1286 - $this->multipleTemplateInstanceTableHTML( $section )
1287 - ) . "\n";
1288 -
12891432 // This will cause the section to be
12901433 // re-parsed on the next go.
12911434 $section_num--;
1292 - } else {
1293 - // This is the last instance of this
1294 - // template - print all the sections
1295 - // necessary for adding additional
1296 - // instances.
1297 - $form_text .= "\t\t" . Xml::tags( 'div',
1298 - array(
1299 - 'class' => "multipleTemplateStarter",
1300 - 'style' => "display: none",
1301 - ),
1302 - $this->multipleTemplateInstanceTableHTML( $section )
1303 - ) . "\n";
1304 - $form_text .= <<<END
1305 - </div><!-- multipleTemplateList -->
1306 - <p style="margin-left:10px;" />
1307 - <p><input type="button" value="$add_button_text" tabindex="$sfgTabIndex" class="multipleTemplateAdder" /></p>
1308 - </div><!-- multipleTemplateWrapper -->
1309 -
1310 -END;
13111435 }
1312 - } else {
 1436+ } else { //if ( $allow_multiple ) {
13131437 $form_text .= $section;
13141438 }
1315 -
 1439+ $curPlaceholder = null;
13161440 } // end for
13171441
 1442+ // Cleanup - everything has been browsed.
 1443+ // Remove all the remaining placeholder
 1444+ // tags in the HTML and wiki-text.
 1445+ foreach ( $placeholderFields as $stringToReplace ) {
 1446+ //remove the @<replacename>@ tags from the data that is submitted
 1447+ $data_text = preg_replace('/'.self::makePlaceholderInWikiText( $stringToReplace ).'/', '',$data_text);
 1448+
 1449+ //remove the @<insertHTML>@ tags from the generated HTML form
 1450+ $form_text = preg_replace( '/' . self::makePlaceholderInFormHTML( $stringToReplace ) . '/', '', $form_text );
 1451+ }
 1452+
13181453 // if it wasn't included in the form definition, add the
13191454 // 'free text' input as a hidden field at the bottom
13201455 if ( ! $free_text_was_included ) {
@@ -1326,16 +1461,16 @@
13271462 // (a) we're processing a replacement (param 'partial' == 1)
13281463 // (b) we're sending out something to be replaced (param 'partial' is missing)
13291464 if ( $form_is_partial ) {
1330 - if ( !$wgRequest->getCheck( 'partial' ) ) {
1331 - $free_text = $original_page_content;
1332 - $form_text .= SFFormUtils::hiddenFieldHTML( 'partial', 1 );
1333 - } else {
1334 - $free_text = null;
1335 - $existing_page_content = preg_replace( array( '/�\{/m','/\}�/m' ),
1336 - array( '{{','}}' ),
1337 - $existing_page_content );
1338 - $existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}/', '', $existing_page_content );
1339 - }
 1465+ if ( !$wgRequest->getCheck( 'partial' ) ) {
 1466+ $free_text = $original_page_content;
 1467+ $form_text .= SFFormUtils::hiddenFieldHTML( 'partial', 1 );
 1468+ } else {
 1469+ $free_text = null;
 1470+ $existing_page_content = preg_replace( array( '/�\{/m','/\}�/m' ),
 1471+ array( '{{','}}' ),
 1472+ $existing_page_content );
 1473+ $existing_page_content = preg_replace( '/\{\{\{insertionpoint\}\}\}/', '', $existing_page_content );
 1474+ }
13401475 } elseif ( $source_is_page ) {
13411476 // if the page is the source, free_text will just be whatever in the
13421477 // page hasn't already been inserted into the form
@@ -1420,7 +1555,7 @@
14211556 if ( $wgRequest->getCheck( 'partial' ) )
14221557 $data_text = $existing_page_content;
14231558
1424 - if ( !$embedded ) {
 1559+ if ( !$is_embedded ) {
14251560 $form_page_title = $wgParser->recursiveTagParse( str_replace( "{{!}}", "|", $form_page_title ) );
14261561 } else {
14271562 $form_page_title = null;

Follow-up revisions

RevisionCommit summaryAuthorDate
r97888Follow-up to r96581 - added additional patch from LY Meng to fix display of "...yaron05:50, 23 September 2011

Comments

#Comment by Nikerabbit (talk | contribs)   17:02, 8 September 2011

Garbled encoding near line 1326.

#Comment by Yaron Koren (talk | contribs)   18:13, 8 September 2011

That's true, although... it's not garbled any worse than it was before, is it? I think I only removed some extra spaces there. I honestly don't remember what those characters are, but I assume they work.