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