http://www.mediawiki.org/wiki/Special:Code/MediaWiki/96581

Revision: 96581
Author:   yaron
Date:     2011-09-08 16:22:56 +0000 (Thu, 08 Sep 2011)
Log Message:
-----------
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: trunk/extensions/SemanticForms/includes/SF_FormPrinter.php
===================================================================
--- trunk/extensions/SemanticForms/includes/SF_FormPrinter.php  2011-09-08 
16:13:27 UTC (rev 96580)
+++ trunk/extensions/SemanticForms/includes/SF_FormPrinter.php  2011-09-08 
16:22:56 UTC (rev 96581)
@@ -8,6 +8,7 @@
  * @author Harold Solbrig
  * @author Daniel Hansch
  * @author Stephan Gambke
+ * @author LY Meng
  * @file
  * @ingroup SF
  */
@@ -218,6 +219,18 @@
                }
        }
 
+       static function placeholderFormat( $templateName, $fieldName ) {
+               return $templateName . '___' . $fieldName;
+       }
+
+       static function makePlaceholderInWikiText( $str ) {
+               return '@replace_' . $str . '@';
+       }
+
+       static function makePlaceholderInFormHTML( $str ) {
+               return '@insertHTML_' . $str . '@';
+       }
+
        /**
         * Creates the HTML for the inner table for every instance of a
         * multiple-instance template in the form.
@@ -248,6 +261,53 @@
        }
 
        /**
+        * Creates the HTML for a single instance of a multiple-instance 
template;
+        * plus the end tags for the full multiple-instance HTML.
+        */
+       function multipleTemplateInstanceHTML( $all_instances_printed, 
&$section, $instance_num, $add_button_text ) {
+               global $sfgTabIndex;
+
+               if ( ! $all_instances_printed ) {
+                       // Add the character "a" onto the instance number of 
this input
+                       // in the form, to differentiate the inputs the form 
starts out
+                       // with from any inputs added by the Javascript.
+                       $section = str_replace( '[num]', "[{$instance_num}a]", 
$section );
+                       // @TODO - this replacement should be
+                       // case- and spacing-insensitive
+                       $section = str_replace( ' id=', ' origID=', $section );
+                       $text = "\t\t" . Xml::tags( 'div',
+                               array(
+                                       // The "multipleTemplate" class is 
there for
+                                       // backwards-compatibility with any 
custom CSS on people's
+                                       // wikis before SF 2.0.9.
+                                       'class' => "multipleTemplateInstance 
multipleTemplate"
+                               ),
+                               $this->multipleTemplateInstanceTableHTML( 
$section )
+                       ) . "\n";
+
+               } else { //if ( $all_instances_printed ) {
+                       // This is the last instance of this
+                       // template - print all the sections
+                       // necessary for adding additional
+                       // instances.
+                       $text = "\t\t" . Xml::tags( 'div',
+                               array(
+                                       'class' => "multipleTemplateStarter",
+                                       'style' => "display: none",
+                               ),
+                               $this->multipleTemplateInstanceTableHTML( 
$section )
+                       ) . "\n";
+                       $text .= <<<END
+       </div><!-- multipleTemplateList -->
+               <p style="margin-left:10px;" />
+               <p><input type="button" value="$add_button_text" 
tabindex="$sfgTabIndex" class="multipleTemplateAdder" /></p>
+       </div><!-- multipleTemplateWrapper -->
+END;
+               }
+               return $text;
+       }
+
+       /**
         * This function is the real heart of the entire Semantic Forms
         * extension. It handles two main actions: (1) displaying a form on the
         * screen, given a form definition and possibly page contents (if an
@@ -257,7 +317,7 @@
         * It also does some related tasks, like figuring out the page name (if
         * only a page formula exists).
         */
-       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 ) {
+       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 ) {
                global $wgRequest, $wgUser, $wgOut, $wgParser;
                global $sfgTabIndex; // used to represent the current tab index 
in the form
                global $sfgFieldNum; // used for setting various HTML IDs
@@ -292,10 +352,10 @@
                        $original_page_content = $existing_page_content;
                } else {
                        $original_page_content = null;
-                        if ( $wgRequest->getCheck( 'free_text' ) ) {
-                                       $existing_page_content = 
$wgRequest->getVal( 'free_text' );
-                                       $form_is_partial = true;
-                        }
+                       if ( $wgRequest->getCheck( 'free_text' ) ) {
+                               $existing_page_content = $wgRequest->getVal( 
'free_text' );
+                               $form_is_partial = true;
+                       }
                }
 
                // Disable all form elements if user doesn't have edit
@@ -303,7 +363,7 @@
                // editing permissions can be set in different ways.
                // HACK - sometimes we don't know the page name in advance, but
                // we still need to set a title here for testing permissions.
-               if ( $embedded ) {
+               if ( $is_embedded ) {
                        // If this is an embedded form (probably a 'RunQuery'),
                        // just use the name of the actual page we're on.
                        global $wgTitle;
@@ -419,6 +479,14 @@
                $instance_num = 0;
                $all_instances_printed = false;
                $strict_parsing = false;
+               
+               // Placeholder name in the form
+               $curPlaceholder = null;
+               // Used to store the HTML code of the multiple template, to 
reinsert it into the right spot     
+               $multipleTemplateString = "";   
+               // This array will keep track of all the replaced @<name>@ 
strings
+               $placeholderFields = array();   
+               
                for ( $section_num = 0; $section_num < count( 
$form_def_sections ); $section_num++ ) {
                        $start_position = 0;
                        $template_text = "";
@@ -426,6 +494,9 @@
                        // array doesn't get modified; is it necessary?
                        $section = " " . $form_def_sections[$section_num];
 
+                       
+                       $multipleTemplateString="";
+                       
                        while ( $brackets_loc = strpos( $section, '{{{', 
$start_position ) ) {
                                $brackets_end_loc = strpos( $section, "}}}", 
$brackets_loc );
                                $bracketed_string = substr( $section, 
$brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) );
@@ -454,29 +525,47 @@
                                                                $template_label 
= $sub_components[1];
                                                        } elseif ( 
$sub_components[0] == 'add button text' ) {
                                                                
$add_button_text = $sub_components[1];
+                                                       } elseif 
($sub_components[0] == 'embed in field') {
+                                                               // Placeholder 
on form template level. Assume that the template form def
+                                                               // will have a 
multiple+placeholder parameters, and get the placeholder value.
+                                                               // We expect 
something like TemplateName[fieldName], and convert it to the
+                                                               // 
TemplateName___fieldName form used internally.
+                                                               preg_match( 
'/\s*(.*)\[(.*)\]\s*/', $sub_components[1], $matches );
+                                                               $curPlaceholder 
= ( count( $matches ) > 2 ) ? self::placeholderFormat( $matches[1], $matches[2] 
) : null;
+                                                               unset 
($matches);
                                                        }
                                                }
                                        }
-                                       // If this is the first instance, add 
the label into the form, if
-                                       // there is one, and add the 
appropriate wrapper div, if this is
-                                       // a multiple-instance template.
+                                       // If this is the first instance, add
+                                       // the label into the form, if there is
+                                       // one, and add the appropriate wrapper
+                                       // div, if this is a multiple-instance
+                                       // template.
                                        if ( $old_template_name != 
$template_name ) {
                                                if ( isset( $template_label ) ) 
{
                                                        $form_text .= 
"<fieldset>\n";
                                                        $form_text .= 
"<legend>$template_label</legend>\n";
                                                }
-                                               if ($allow_multiple) {
-                                                       $form_text .= "\t" . 
'<div class="multipleTemplateWrapper">' . "\n";
-                                                       $form_text .= "\t" . 
'<div class="multipleTemplateList">' . "\n";
-                                               }
+                                               // If $curPlaceholder is set, 
it means we want to insert a
+                                               // multiple template form's 
HTML into the main form's HTML.
+                                               // So, the HTML will be stored 
in $multipleTemplateString.
+                                               if ($allow_multiple) {          
                                
+                                                       $multipleTemplateString 
.= "\t" . '<div class="multipleTemplateWrapper">' . "\n";
+                                                       $multipleTemplateString 
.= "\t" . '<div class="multipleTemplateList">' . "\n";
+                                                       if ( $curPlaceholder == 
null ) {
+                                                               $form_text .= 
$multipleTemplateString;                                          
+                                                       }
+                                               }
                                        }
                                        $template_text .= "{{" . $template_name;
                                        $all_fields = $tif->getAllFields();
                                        // remove template tag
                                        $section = substr_replace( $section, 
'', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc );
                                        $template_instance_query_values = 
$wgRequest->getArray( $query_template_name );
-                                       // If we are editing a page, and this 
template can be found more than
-                                       // once in that page, and multiple 
values are allowed, repeat this
+                                       // If we are editing a page, and this
+                                       // template can be found more than
+                                       // once in that page, and multiple
+                                       // values are allowed, repeat this
                                        // section.
                                        $existing_template_text = null;
                                        if ( $source_is_page || 
$form_is_partial ) {
@@ -639,7 +728,7 @@
                                        $instance_num = 0;
                                // 
=====================================================
                                // field processing
-                               // 
=====================================================        
+                               // 
=====================================================
                                } elseif ( $tag_title == 'field' ) {
                                        $field_name = trim( $tag_components[1] 
);
                                        // cycle through the other components
@@ -656,6 +745,7 @@
                                        $possible_values = null;
                                        $semantic_property = null;
                                        $preload_page = null;
+                                       $holds_template = false;
                                        for ( $i = 2; $i < count( 
$tag_components ); $i++ ) {
                                                $component = trim( 
$tag_components[$i] );
                                                if ( $component == 'mandatory' 
) {
@@ -681,6 +771,12 @@
                                                        if ( count( 
$sub_components ) == 1 ) {
                                                                // add handling 
for single-value params, for custom input types
                                                                
$field_args[$sub_components[0]] = null;
+
+                                                               if ( $component 
== 'holds template' ) {
+                                                                       
$is_hidden = true;
+                                                                       
$holds_template = true;
+                                                                       
$placeholderFields[] = self::placeholderFormat( $template_name, $field_name );
+                                                               } 
                                                        } elseif ( count( 
$sub_components ) == 2 ) {
                                                                // First, set 
each value as its own entry in $field_args.
                                                                
$field_args[$sub_components[0]] = $sub_components[1];
@@ -767,10 +863,11 @@
                                                                        
$field_args['default filename'] = $default_filename;
                                                                } elseif ( 
$sub_components[0] == 'restricted' ) {
                                                                        
$is_restricted = !array_intersect(
-                                                                               
        $wgUser->getEffectiveGroups(),
-                                                                               
        array_map( 'trim', explode( ',', $sub_components[1] ) )
+                                                                               
$wgUser->getEffectiveGroups(),
+                                                                               
array_map( 'trim', explode( ',', $sub_components[1] ) )
                                                                        );
                                                                }
+
                                                        }
                                                }
                                        } // end for
@@ -824,15 +921,28 @@
                                                }
                                        }
 
-                                       // if the user is editing a page, and 
that page contains a call to
+                                       // If the user is editing a page, and 
that page contains a call to
                                        // the template being processed, get 
the current field's value
                                        // from the template call
                                        if ( $source_is_page && ( ! empty( 
$existing_template_text ) ) ) {
                                                if ( isset( 
$template_contents[$field_name] ) ) {
                                                        $cur_value = 
$template_contents[$field_name];
-                                                       // now remove this 
value from $template_contents, so that
-                                                       // at the end we can 
have a list of all the fields that
-                                                       // weren't handled by 
the form
+
+                                                       // If the field is a 
placeholder, the contents of this template
+                                                       // parameter should be 
treated as elements parsed by an another
+                                                       // multiple template 
form.
+                                                       // By putting that at 
the very end of the parsed string, we'll
+                                                       // have it processed as 
a regular multiple template form.
+                                                       if ( $holds_template ) {
+                                                               
$existing_page_content = $existing_page_content . $cur_value;
+                                                       }
+
+                                                       // Now remove this value
+                                                       // from 
$template_contents,
+                                                       // so that at the end we
+                                                       // can have a list of 
all
+                                                       // the fields that 
weren't
+                                                       // handled by the form.
                                                        unset( 
$template_contents[$field_name] );
                                                } else {
                                                        $cur_value = '';
@@ -1030,9 +1140,9 @@
                                                }
                                                // increment the global field 
number regardless
                                                $sfgFieldNum++;
-                                               // if the field is a date 
field, and its default value was set
+                                               // If the field is a date 
field, and its default value was set
                                                // to 'now', and it has no 
current value, set $cur_value to be
-                                               // the current date
+                                               // the current date.
                                                if ( $default_value == 'now' &&
                                                                // if the date 
is hidden, cur_value will already be set
                                                                // to the 
default value
@@ -1082,9 +1192,9 @@
                                                                }
                                                        }
                                                }
-                                               // if the field is a text 
field, and its default value was set
+                                               // If the field is a text 
field, and its default value was set
                                                // to 'current user', and it 
has no current value, set $cur_value
-                                               // to be the current user
+                                               // to be the current user.
                                                if ( $default_value == 'current 
user' &&
                                                                // if the date 
is hidden, cur_value will already be set
                                                                // to the 
default value
@@ -1094,11 +1204,26 @@
                                                                $cur_value = 
$cur_value_in_template;
                                                        }
                                                }
+                                               
+                                               // Generate a hidden field with 
a placeholder value that will be replaced
+                                               // by the multiple-instances 
template output at form submission.
+                                               ////<input type="hidden" 
value="@replace_Town___mayors@" name="Town[town_mayors]" />
+                                               if ( $holds_template ) {
+                                                       $cur_value = 
self::makePlaceholderInWikiText( 
self::placeholderFormat($template_name,$field_name) );
+                                               }
+                       
                                                $new_text = 
$this->formFieldHTML( $form_field, $cur_value );
 
-                                               // if this field is disabled, 
add a hidden field holding
+                                               // Add a field just after the 
hidden field, within the HTML, to locate 
+                                               // where the multiple-templates 
HTML, stored in $multipleTemplateString,
+                                               // should be inserted.
+                                               if ( $holds_template ) {
+                                                       $new_text .= 
self::makePlaceholderInFormHTML( self::placeholderFormat( $template_name, 
$field_name ) );
+                                               }
+                                               
+                                               // If this field is disabled, 
add a hidden field holding
                                                // the value of this field, 
because disabled inputs for some
-                                               // reason don't submit their 
value
+                                               // reason don't submit their 
value.
                                                if ( $form_field->isDisabled() 
) {
                                                        if ( $field_name == 
'free text' || $field_name == '<freetext>' ) {
                                                                $new_text .= 
SFFormUtils::hiddenFieldHTML( 'free_text', '!free_text!' );
@@ -1247,8 +1372,26 @@
                                                $template_text .= 
SFFormUtils::addUnhandledFields( $template_name );
                                        }
                                        $template_text .= "}}";
-                                       $data_text .= $template_text . "\n";
-                                       // If there is a placeholder in the 
text, we know that we are
+                                       
+                                       
+                                       
+                                       /*used on submission on the template 
form level
+                                        1. the base $template_text  will 
contain strings like "@replace_xxx@" in the hidden fields when the form will be 
submitted     
+                                        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
+                                        the trailing @replace_xxx@ will be 
deleted at the end with the data from 
+                                       
+                                               note: this clean up step could 
also be done with a regexp instead of keeping a track array /@replace_(.*)@/    
         
+                                       */
+                                       
+                                       $reptmp = 
self::makePlaceholderInWikiText( $curPlaceholder );
+                                       if ( $curPlaceholder != null && 
$data_text && strpos( $data_text, $reptmp, 0 ) !== false) {
+                                               $data_text = preg_replace( '/' 
. $reptmp . '/', $template_text . $reptmp, $data_text );
+                                       } else {
+                                               $data_text .= $template_text . 
"\n";
+                                       }
+
+                                       // If there is a placeholder in the
+                                       // text, we know that we are
                                        // doing a replace.
                                        if ( $existing_page_content && strpos( 
$existing_page_content, '{{{insertionpoint}}}', 0 ) !== false ) {
                                                $existing_page_content = 
preg_replace( '/\{\{\{insertionpoint\}\}\}(\r?\n?)/',
@@ -1267,53 +1410,45 @@
                        }
 
                        if ( $allow_multiple ) {
+                               if ( $curPlaceholder == null ) {
+                                       // The normal process.
+                                       $form_text .= 
$this->multipleTemplateInstanceHTML( $all_instances_printed, $section, 
$instance_num, $add_button_text );
+                               } else { // if ( $curPlaceholder != null ){
+                                       // The template text won't be appended 
at the end of the template like for usual multiple template forms.
+                                       // The HTML text will then be stored in 
the $multipleTemplateString variable,
+                                       // and then added in the right 
@insertHTML_".$placeHolderField."@"; position
+                                       // Optimization: actually, instead of 
separating the processes, the usual multiple
+                                       // template forms could also be handled 
this way if a fitting placeholder tag was added.
+                                       $multipleTemplateString .= 
$this->multipleTemplateInstanceHTML( $all_instances_printed, $section, 
$instance_num, $add_button_text );
+                                       // We replace the 
$multipleTemplateString HTML into the
+                                       // current placeholder tag, but also 
add another
+                                       // placeholder tag, to keep track of it.
+                                       $multipleTemplateString .= 
self::makePlaceholderInFormHTML( $curPlaceholder );
+                                       $form_text = preg_replace( '/' . 
self::makePlaceholderInFormHTML( $curPlaceholder ) . '/',
+                                              $multipleTemplateString, 
$form_text );
+                               }
                                if ( ! $all_instances_printed ) {
-                                       // Add the character "a" onto the 
instance number of this input
-                                       // in the form, to differentiate the 
inputs the form starts out
-                                       // with from any inputs added by the 
Javascript.
-                                       $section = str_replace( '[num]', 
"[{$instance_num}a]", $section );
-                                       // @TODO - this replacement should be
-                                       // case- and spacing-insensitive
-                                       $section = str_replace( ' id=', ' 
origID=', $section );
-                                       $form_text .= "\t\t" . Xml::tags( 'div',
-                                               array(
-                                                       // The 
"multipleTemplate" class is there for
-                                                       // 
backwards-compatibility with any custom CSS on people's
-                                                       // wikis before SF 
2.0.9.
-                                                       'class' => 
"multipleTemplateInstance multipleTemplate"
-                                               ),
-                                               
$this->multipleTemplateInstanceTableHTML( $section )
-                                       ) . "\n";
-
                                        // This will cause the section to be
                                        // re-parsed on the next go.
                                        $section_num--;
-                               } else {
-                                       // This is the last instance of this
-                                       // template - print all the sections
-                                       // necessary for adding additional
-                                       // instances.
-                                       $form_text .= "\t\t" . Xml::tags( 'div',
-                                               array(
-                                                       'class' => 
"multipleTemplateStarter",
-                                                       'style' => "display: 
none",
-                                               ),
-                                               
$this->multipleTemplateInstanceTableHTML( $section )
-                                       ) . "\n";
-                                       $form_text .= <<<END
-       </div><!-- multipleTemplateList -->
-               <p style="margin-left:10px;" />
-               <p><input type="button" value="$add_button_text" 
tabindex="$sfgTabIndex" class="multipleTemplateAdder" /></p>
-       </div><!-- multipleTemplateWrapper -->
-
-END;
                                }
-                       } else {
+                       } else { //if ( $allow_multiple ) {
                                $form_text .= $section;
                        }
-
+                       $curPlaceholder = null;
                } // end for
 
+               // Cleanup - everything has been browsed.
+               // Remove all the remaining placeholder
+               // tags in the HTML and wiki-text.
+               foreach ( $placeholderFields as $stringToReplace ) {
+                       //remove the @<replacename>@ tags from the data that is 
submitted
+                       $data_text = 
preg_replace('/'.self::makePlaceholderInWikiText( $stringToReplace ).'/', 
'',$data_text);  
+                       
+                       //remove the @<insertHTML>@ tags from the generated 
HTML form
+                       $form_text = preg_replace( '/' . 
self::makePlaceholderInFormHTML( $stringToReplace ) . '/', '', $form_text );   
+               }
+               
                // if it wasn't included in the form definition, add the
                // 'free text' input as a hidden field at the bottom
                if ( ! $free_text_was_included ) {
@@ -1326,16 +1461,16 @@
                // (a) we're processing a replacement (param 'partial' == 1)
                // (b) we're sending out something to be replaced (param 
'partial' is missing)
                if ( $form_is_partial ) {
-                        if ( !$wgRequest->getCheck( 'partial' ) ) {
-                                $free_text = $original_page_content;
-                                $form_text .= SFFormUtils::hiddenFieldHTML( 
'partial', 1 );
-                        } else {
-                                $free_text = null;
-                                $existing_page_content = preg_replace( array( 
'/�\{/m','/\}�/m' ),
-                                        array( '{{','}}' ),
-                                        $existing_page_content );
-                                $existing_page_content = preg_replace( 
'/\{\{\{insertionpoint\}\}\}/', '', $existing_page_content );
-                        }
+                       if ( !$wgRequest->getCheck( 'partial' ) ) {
+                               $free_text = $original_page_content;
+                               $form_text .= SFFormUtils::hiddenFieldHTML( 
'partial', 1 );
+                       } else {
+                               $free_text = null;
+                               $existing_page_content = preg_replace( array( 
'/�\{/m','/\}�/m' ),
+                                       array( '{{','}}' ),
+                                       $existing_page_content );
+                               $existing_page_content = preg_replace( 
'/\{\{\{insertionpoint\}\}\}/', '', $existing_page_content );
+                       }
                } elseif ( $source_is_page ) {
                        // if the page is the source, free_text will just be 
whatever in the
                        // page hasn't already been inserted into the form
@@ -1420,7 +1555,7 @@
                if ( $wgRequest->getCheck( 'partial' ) )
                        $data_text = $existing_page_content;
 
-               if ( !$embedded ) {
+               if ( !$is_embedded ) {
                        $form_page_title = $wgParser->recursiveTagParse( 
str_replace( "{{!}}", "|", $form_page_title ) );
                } else {
                        $form_page_title = null;


_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to