Content-Type: multipart/mixed; boundary=Apple-Mail-45--365610717 --Apple-Mail-45--365610717 Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset=us-ascii http://practicalplants.org/wiki), I needed to be able to control the HTML which was output by = multiple template instances. Currently the HTML is hardcoded within the = SF parser and there are no hooks available to modify it's output. While = my need may be a fringe case, I think hardcoded HTML with no way to = override it encourages hacking the core files: A Very Bad Thing. I'd = like to submit my changes for inclusion into SF core, so I'm looking for = feedback on the changes I'm proposing. I've attached a patch for = SF_FormPrinter.php and SemanticForms.php and a new class file = SF_MultipleTemplate.php, at the end of this = email. 

I've made the following SF hooks = available to modify the HTML output of a multiple template instance. In = order to make these hooks flexible, I wanted to be able to supply an = object instance which contained information about the Multiple Template = Instance being parsed. To do this, I extracted most of the logic for = outputting multiple template instances into a new class = SFMultipleTemplate which is responsible for defining the default = HTML (which is currently hardcoded in SFFormPrinter),  and = for running the following hooks, which it passes the default html = by reference to allow for modification, and the = SFMultipleTemplate instance which is calling the hook, to = give access to data about the Multiple Template Instance in = question.

Here are the hooks I've created, = based on the default HTML currently = used.

sfMultipleInstanceTemplateBefore= HTML (String &$html, SFMultipleTemplate = $template)
Allows the customisation of the HTML which is = output before the list of template = instances. 

sfMultipleInsta= nceTemplateAfterHTML (String = &$html, SFMultipleTemplate $template)
A= llows the customisation of the HTML which is output after the list of = template = instances.

sfMultipleInstanceTemplateHTML (String &$html, String = $content, SFMultipleTemplate $template)
All= ows the customisation of the html which wraps a multiple template = instance = item.

sfMultipleInstanceTemplateA= dderHTML (String &$html, String = $content, SFMultipleTemplate $template)
Same as above, except this sets the hidden multiple template = instance item which is cloned by the frontend javascript when the add = button is = clicked.

sfMultipleInstanceTemplateInnerHTM= L (String &$html, String = $section, SFMultipleTemplate $template)
All= ows the customisation of the html of the multiple template instance = item. The html returned by this must contain the close and reorder = icons. Passing some isolated default html for those icons, or providing = get methods in SFMultipleTemplate might be a good = idea.



Practic= al Plants Use Case
I use these hooks to render = multiple template instance items as rows of a table for my references. = You can see it in action here:

http://practicalplants.org/w/index.php?titl= e=3DMalus_domestica&action=3Dformedit#References

This is implemented with the following hook handlers in my = skin's related extension. Note that by extracting the Multiple Template = Instance functionality into an object, I am able to check the template = name to customise output on a per-instance = basis. 

function = sfMultipleInstanceTemplateBeforeHTML(&$html, = $template){
= if($template->template_name =3D=3D=3D = 'Reference'){
$html =3D = '
= <div = class=3D"multipleTemplateWrapper">
= <table class=3D"table">
= <thead>
<th = class=3D"ref-type">Type</th>
= <th class=3D"ref-id">Identifier</th>
= <th class=3D"ref-author">Author</th>
= <th class=3D"ref-title">Title</th>
= <th class=3D"ref-source">Source</th>
= <th class=3D"ref-url">URL/ISBN</th>
= <th class=3D"ref-date">Date</th>
= <th class=3D"ref-buttons"></th>
= </thead>
<tbody = class=3D"multipleTemplateList">';
= }
return = true;
= }
function = sfMultipleInstanceTemplateAfterHTML(&$html, = $template){
= if($template->template_name =3D=3D=3D = 'Reference'){
$html =3D = '</tbody></table>';
$html .=3D = $template->addButtonHTML();
$html .=3D = '</div>';
}
= return true;
}
function = sfMultipleInstanceTemplateHTML(&$html, $content, = $template){
= if($template->template_name =3D=3D=3D = 'Reference'){
$html =3D '<tr = class=3D"multipleTemplateInstance = multipleTemplate">'.$content.'</tr>';
= }
return = true;
= }

function = sfMultipleInstanceTemplateAdderHTML(&$html, $content, = $template){
= if($template->template_name =3D=3D=3D = 'Reference'){
$html =3D '<tr = class=3D"multipleTemplateStarter" = style=3D"display:none">'.$content.'</tr>';
= }
return = true;
= }

function = sfMultipleInstanceTemplateInnerHTML(&$html, $section, = $template){
global = $sfgScriptPath;
= if($template->template_name =3D=3D=3D = 'Reference'){
  //we = have to str_replace some faux td elements since mediawiki doesn't allow = <td> elements in wikitext without an enclosing table = element
$html =3D   = str_replace('-!/td!-','</td>',str_replace('-!td!-', '<td>', = $section)).'<td>'
. = '<span class=3D"removeButton"><a class=3D"btn btn-link = remover"><i = class=3D"icon-remove"></i></a></span>'
= . '<span class=3D"instanceRearranger"><img = src=3D"'.$sfgScriptPath.'/skins/rearranger.png" = class=3D"rearrangerImage"></span>'
= . '</td>';
}
= return true;
= }





Patch for = SF_FormPrinter.php
= --Apple-Mail-45--365610717 Content-Disposition: attachment; filename=SF_FormPrinter.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="SF_FormPrinter.patch" Content-Transfer-Encoding: 7bit --- SF_FormPrinter.php 2012-10-28 13:51:50.000000000 +0100 +++ SF_FormPrinter-new.php 2012-10-28 13:56:10.000000000 +0100 @@ -229,92 +229,7 @@ return '@insertHTML_' . $str . '@'; } - /** - * Creates the HTML for the inner table for every instance of a - * multiple-instance template in the form. - */ - function multipleTemplateInstanceTableHTML( $form_is_disabled, $mainText ) { - global $sfgTabIndex, $sfgScriptPath; - - $attributes = array( - 'tabindex' => $sfgTabIndex, - 'class' => 'remover', - ); - - $rearranger = 'class="rearrangerImage"'; - - if ( $form_is_disabled ) { - $attributes['disabled'] = 'disabled'; - $rearranger = ''; - } - - $removeButton = Html::input( null, wfMsg( 'sf_formedit_remove' ), 'button', $attributes ); - - $text = << - - $mainText - $removeButton - - - - - -END; - - return $text; - } - - /** - * Creates the HTML for a single instance of a multiple-instance template; - * plus the end tags for the full multiple-instance HTML. - */ - function multipleTemplateInstanceHTML( $form_is_disabled, $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 ); - - $text = "\t\t" . Html::rawElement( '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( $form_is_disabled, $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" . Html::rawElement( 'div', - array( - 'class' => "multipleTemplateStarter", - 'style' => "display: none", - ), - $this->multipleTemplateInstanceTableHTML( $form_is_disabled, $section ) - ) . "\n"; - - $attributes = array( - 'tabindex' => $sfgTabIndex, - 'class' => 'multipleTemplateAdder', - ); - if ( $form_is_disabled ) $attributes['disabled'] = true; - $button = Html::input( null, Sanitizer::decodeCharReferences( $add_button_text ), 'button', $attributes ); - $text .= << -

$button

-
-END; - } - return $text; - } /** * This function is the real heart of the entire Semantic Forms @@ -550,8 +465,10 @@ // multiple template form's HTML into the main form's HTML. // So, the HTML will be stored in $multipleTemplateString. if ( $allow_multiple ) { - $multipleTemplateString .= "\t" . '
' . "\n"; - $multipleTemplateString .= "\t" . '
' . "\n"; + //we want to wrap here + $multipleTemplateInstance = SFMultipleTemplate::getInstance($template_name);//,$form_is_disabled,$section,$instance_num); + $multipleTemplateInstance->setDisabled($form_is_disabled); + $multipleTemplateString.=$multipleTemplateInstance->beforeHTML(); } } if ( $curPlaceholder == null ) { @@ -587,6 +504,7 @@ // the same tags, but I don't know what it is. if ( $found_instance ) { $instance_num++; + $multipleTemplateInstance->increment(); } else { $all_instances_printed = true; } @@ -734,6 +652,7 @@ $allow_multiple = false; $all_instances_printed = false; $instance_num = 0; + $multipleTemplateInstance->instance = 0; // ===================================================== // field processing // ===================================================== @@ -1426,16 +1345,36 @@ } if ( $allow_multiple ) { + $multipleTemplateInstance->setSection($section); if ( $curPlaceholder == null ) { // The normal process. - $form_text .= $this->multipleTemplateInstanceHTML( $form_is_disabled, $all_instances_printed, $section, $instance_num, $add_button_text ); + + // If there are still instances to add, add them, otherwise add the hidden template fields + // and add the add button + if(!$all_instances_printed){ + $form_text .= $multipleTemplateInstance->itemHTML(); + }else{ + //if all the instances have been added + $form_text .= $multipleTemplateInstance->adderHTML(); + $form_text .= $multipleTemplateInstance->afterHTML(); + } + } 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( $form_is_disabled, $all_instances_printed, $section, $instance_num, $add_button_text ); + + // If there are still instances to add, add them, otherwise add the hidden template fields + // and add the add button + if(!$all_instances_printed){ + $multipleTemplateString .= $multipleTemplateInstance->itemHTML(); + }else{ + $multipleTemplateString .= $multipleTemplateInstance->adderHTML(); + $multipleTemplateString .= $multipleTemplateInstance->afterHTML(); + } + // We replace the $multipleTemplateString HTML into the // current placeholder tag, but also add another // placeholder tag, to keep track of it. --Apple-Mail-45--365610717 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii


Patch for SemanticForms.php
--Apple-Mail-45--365610717 Content-Disposition: attachment; filename=SemanticForms.php.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="SemanticForms.php.patch" Content-Transfer-Encoding: 7bit @@ -152,6 +152,8 @@ $wgAutoloadClasses['SFParserFunctions'] = $sfgIP . '/includes/SF_ParserFunctions $wgAutoloadClasses['SFAutocompleteAPI'] = $sfgIP . '/includes/SF_AutocompleteAPI.php'; $wgAutoloadClasses['SFAutoeditAPI'] = $sfgIP . '/includes/SF_AutoeditAPI.php'; $wgAutoloadClasses['SFFormEditAction'] = $sfgIP . '/includes/SF_FormEditAction.php'; +$wgAutoloadClasses['SFMultipleTemplate'] = $sfgIP . '/includes/SF_MultipleTemplate.php'; + // Form inputs $wgAutoloadClasses['SFFormInput'] = $sfgIP . '/includes/forminputs/SF_FormInput.php'; --Apple-Mail-45--365610717 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii


New class file SF_MultipleTemplate.php
--Apple-Mail-45--365610717 Content-Disposition: attachment; filename=SF_MultipleTemplate.php Content-Type: text/php; x-unix-mode=0644; name="SF_MultipleTemplate.php" Content-Transfer-Encoding: 7bit template_name = $template_name; $this->add_button_text = wfMsg( 'sf_formedit_addanother' ); } public function setDisabled($bool=true){ $this->disabled = $bool; } public function setSection($section){ // 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. $this->section = str_replace( '[num]', '['.$this->instance.'a]', $section ); } public function increment(){ $this->instance++; } /** * Creates the HTML for the inner table for every instance of a * multiple-instance template in the form. */ public function innerHTML( ) { global $sfgTabIndex, $sfgScriptPath; $attributes = array( 'tabindex' => $sfgTabIndex, 'class' => 'remover', ); $rearranger = 'class="rearrangerImage"'; if ( $this->disabled ) { $attributes['disabled'] = 'disabled'; $rearranger = ''; } $removeButton = Html::input( null, wfMsg( 'sf_formedit_remove' ), 'button', $attributes ); $html = << $this->section $removeButton END; wfRunHooks( 'sfMultipleInstanceTemplateInnerHTML', array( &$html, &$this->section, $this ) ); return $html; } /** * Creates the HTML for a single instance of a multiple-instance template; * plus the end tags for the full multiple-instance HTML. */ public function itemHTML() { //wrap the content in the inner html $content = $this->innerHTML(); $html = "\t\t" . Html::rawElement( '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" ), $content ) . "\n"; wfRunHooks( 'sfMultipleInstanceTemplateHTML', array( &$html, $content, $this ) ); return $html; } public function adderHTML(){ //wrap the content in the inner html $content = $this->innerHTML(); $html = "\t\t" . Html::rawElement( 'div', array( 'class' => "multipleTemplateStarter", 'style' => "display: none", ), $content ) . "\n"; wfRunHooks( 'sfMultipleInstanceTemplateAdderHTML', array( &$html, &$content, $this ) ); return $html; } function addButtonHTML(){ global $sfgTabIndex; $attributes = array( 'tabindex' => $sfgTabIndex, 'class' => 'multipleTemplateAdder', ); if ( $this->disabled ) $attributes['disabled'] = true; $html = Html::input( null, Sanitizer::decodeCharReferences( $this->add_button_text ), 'button', $attributes ); wfRunHooks( 'sfMultipleInstanceTemplateAddButtonHTML', array( &$html, $this->add_button_text, $attributes, $this ) ); return $html; } function beforeHTML(){ $html = "\t" . '
' . "\n" . "\t" . '
' . "\n"; wfRunHooks( 'sfMultipleInstanceTemplateBeforeHTML', array( &$html, $this ) ); return $html; } function afterHTML(){ $button = $this->addButtonHTML(); $html = '
' . $button .'
'; wfRunHooks( 'sfMultipleInstanceTemplateAfterHTML', array( &$html, $this ) ); return $html; } } --Apple-Mail-45--365610717 Content-Transfer-Encoding: 7bit Content-Type: text/html; charset=us-ascii



Any feedback would be appreciated. I'd love to have this included in the core so I can implement the functionality I need without having a custom core hack!

Thanks
Andru Vallance


--Apple-Mail-45--365610717--