Joeytje50 has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/358555 )
Change subject: Major revamp of core function formHTML ...................................................................... Major revamp of core function formHTML Mainly split up this gigantic function (which was 917 lines long). It also moves several class-wide variables to private class properties, to avoid massive function headers (although they are still kind of massive). In this commit, I only moved the variables that seemed integral to the entire class to be class properties, but of course any other programmers or reviewers are free to modify this to move more variables to the same place, if they want to improve readability. Comments are helpful, but splitting it up maintains readability much more, by assuring programmers the code they are editing isn't going to destroy something in a different function, most of the time. Editing this huge function is really overwhelming when not familiar with it. I am planning to push another commit to add a nicer implementation of autoedit's suggested += and -= notation, but I wanted to get this commit out first, to maintain my own sanity. Change-Id: I1be3f96bb42701a18958613d54c94ab328ddd2ab --- M includes/PF_FormPrinter.php 1 file changed, 801 insertions(+), 700 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/PageForms refs/changes/55/358555/1 diff --git a/includes/PF_FormPrinter.php b/includes/PF_FormPrinter.php index a84fae4..8041675 100644 --- a/includes/PF_FormPrinter.php +++ b/includes/PF_FormPrinter.php @@ -21,6 +21,12 @@ public $standardInputsIncluded; public $mPageTitle; + private $form_is_disabled; // bool + private $source_matches_form; // bool + private $preloaded_free_text= null; // store preloaded free text + private $free_text_was_included; // bool + private $wiki_page; // wiki page object, used all throughout this class + public function __construct() { global $wgPageFormsDisableOutsideServices; // Initialize variables. @@ -303,8 +309,8 @@ * Creates the HTML for the inner table for every instance of a * multiple-instance template in the form. */ - function multipleTemplateInstanceTableHTML( $form_is_disabled, $mainText ) { - if ( $form_is_disabled ) { + function multipleTemplateInstanceTableHTML($mainText ) { + if ( $this->form_is_disabled ) { $addAboveButton = $removeButton = ''; } else { $addAboveButton = Html::element( 'a', array( 'class' => "addAboveButton", 'title' => wfMessage( 'pf_formedit_addanotherabove' )->text() ) ); @@ -329,7 +335,7 @@ * Creates the HTML for a single instance of a multiple-instance * template. */ - function multipleTemplateInstanceHTML( $template_in_form, $form_is_disabled, &$section ) { + function multipleTemplateInstanceHTML( $template_in_form, &$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. @@ -354,7 +360,7 @@ // wikis before PF 2.0.9. 'class' => "multipleTemplateInstance multipleTemplate" ), - $this->multipleTemplateInstanceTableHTML( $form_is_disabled, $section ) + $this->multipleTemplateInstanceTableHTML( $section ) ) . "\n"; return $text; @@ -364,7 +370,7 @@ * Creates the end of the HTML for a multiple-instance template - * including the sections necessary for adding additional instances. */ - function multipleTemplateEndHTML( $template_in_form, $form_is_disabled, $section ) { + function multipleTemplateEndHTML( $template_in_form, $section ) { global $wgPageFormsTabIndex; $text = "\t\t" . Html::rawElement( 'div', @@ -372,14 +378,14 @@ 'class' => "multipleTemplateStarter", 'style' => "display: none", ), - $this->multipleTemplateInstanceTableHTML( $form_is_disabled, $section ) + $this->multipleTemplateInstanceTableHTML( $section ) ) . "\n"; $attributes = array( 'tabindex' => $wgPageFormsTabIndex, 'class' => 'multipleTemplateAdder', ); - if ( $form_is_disabled ) { + if ( $this->form_is_disabled ) { $attributes['disabled'] = true; } $button = Html::input( null, Sanitizer::decodeCharReferences( $template_in_form->getAddButtonText() ), 'button', $attributes ); @@ -643,12 +649,771 @@ return ''; } + // Function to handle {{{for template}}} tags + private function tagForTemplate(&$tif, &$template, &$existing_page_content, $tag_components, $template_name, $source_is_page) { + // first, obtain if the form is partially submitted again: + global $wgRequest; + $partial_form_submitted = $wgRequest->getCheck( 'partial' ); + + if ( $tif ) { + $previous_template_name = $tif->getTemplateName(); + } else { + $previous_template_name = ''; + } + $template_name = str_replace( '_', ' ', $tag_components[1] ); + $is_new_template = ( $template_name != $previous_template_name ); + if ( $is_new_template ) { + $template = PFTemplate::newFromName( $template_name ); + $tif = PFTemplateInForm::newFromFormTag( $tag_components ); + } + // 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. + if ( $source_is_page || $partial_form_submitted ) { + $tif->setPageRelatedInfo( $existing_page_content ); + // Get the first instance of + // this template on the page + // being edited, even if there + // are more. + if ( $tif->pageCallsThisTemplate() ) { + $tif->setFieldValuesFromPage( $existing_page_content ); + $existing_template_text = $tif->getFullTextInPage(); + // Now remove this template from the text being edited. + // If this is a partial form, establish a new insertion point. + if ( $existing_page_content && $partial_form_submitted ) { + // If something already exists, set the new insertion point + // to its position; otherwise just let it lie. + if ( strpos( $existing_page_content, $existing_template_text ) !== false ) { + $existing_page_content = str_replace( "\n" . '{{{insertionpoint}}}', '', $existing_page_content ); + $existing_page_content = str_replace( $existing_template_text, '{{{insertionpoint}}}', $existing_page_content ); + } + } else { + $existing_page_content = $this->strReplaceFirst( $existing_template_text, '', $existing_page_content ); + } + // If we've found a match in the source + // page, there's a good chance that this + // page was created with this form - note + // that, so we don't send the user a warning. + $this->source_matches_form = true; + } + } + } + + // Function to handle {{{field}}} tags + // @return the value to add to the $placeholderFields array + private function tagField( + &$tif, + &$template, + &$existing_page_content, + &$section, + $tag_components, + $template_name, + $source_is_page, + $form_submitted, + $brackets_loc, + $brackets_end_loc + ) { + global $wgPageFormsTabIndex; // used to represent the current tab index in the form + global $wgPageFormsFieldNum; // used for setting various HTML IDs + $placeholdFieldText = null; + + // If the template is null, that (hopefully) + // means we're handling the free text field. + // Make the template a dummy variable. + if ( $tif == null ) { + $template = new PFTemplate( null, array() ); + $tif = new PFTemplateInForm(); + } + // We get the field name both here + // and in the PFFormField constructor, + // because PFFormField isn't equipped + // to deal with the #freetext# hack, + // among others. + $field_name = trim( $tag_components[1] ); + $form_field = PFFormField::newFromFormFieldTag( $tag_components, $template, $tif, $this->form_is_disabled ); + // For special displays, add in the + // form fields, so we know the data + // structure. + if ( ( $tif->getDisplay() == 'table' && ( !$tif->allowsMultiple() || $tif->getInstanceNum() == 0 ) ) || + ( $tif->getDisplay() == 'spreadsheet' && $tif->allowsMultiple() && $tif->getInstanceNum() == 0 ) ) { + $tif->addField( $form_field ); + } + $cur_value = $form_field->getCurrentValue( $tif->getValuesFromSubmit(), $form_submitted, $source_is_page, $tif->allInstancesPrinted() ); + if ( $form_field->holdsTemplate() ) { + $placeholdFieldText = self::placeholderFormat( $tif->getTemplateName(), $field_name ); + } + + // 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 && ( $tif->getFullTextInPage() != '' && !$form_submitted ) ) { + if ( $tif->hasValueFromPageForField( $field_name ) ) { + // Get value, and remove it, + // so that at the end we + // can have a list of all + // the fields that weren't + // handled by the form. + $cur_value = $tif->getAndRemoveValueFromPageForField( $field_name ); + + // 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 ( $form_field->holdsTemplate() ) { + $existing_page_content .= $cur_value; + } + } elseif ( isset( $cur_value ) && !empty( $cur_value ) ) { + // Do nothing. + } else { + $cur_value = ''; + } + } + + // Handle the free text field. + if ( $field_name == '#freetext#' ) { + // If there was no preloading, this will just be blank. + $this->preloaded_free_text = $cur_value; + // Add placeholders for the free text in both the form and + // the page, using <free_text> tags - once all the free text + // is known (at the end), it will get substituted in. + if ( $form_field->isHidden() ) { + $new_text = Html::hidden( 'pf_free_text', '!free_text!' ); + } else { + $wgPageFormsTabIndex++; + $wgPageFormsFieldNum++; + if ( $cur_value === '' || is_null( $cur_value ) ) { + $default_value = '!free_text!'; + } else { + $default_value = $cur_value; + } + $freeTextInput = new PFTextAreaInput( $input_number = null, $default_value, 'pf_free_text', ( $this->form_is_disabled || $form_field->isRestricted() ), $form_field->getFieldArgs() ); + $freeTextInput->addJavaScript(); + $new_text = $freeTextInput->getHtmlText(); + if ( $form_field->hasFieldArg( 'edittools' ) ) { + // borrowed from EditPage::showEditTools() + $edittools_text = $wgParser->recursiveTagParse( wfMessage( 'edittools', array( 'content' ) )->text() ); + + $new_text .= <<<END +<div class="mw-editTools"> +$edittools_text +</div> + +END; + } + } + $this->free_text_was_included = true; + $this->wiki_page->addFreeTextSection(); + } + + if ( $tif->getTemplateName() === '' || $field_name == '#freetext#' ) { + $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + } else { + if ( is_array( $cur_value ) ) { + // @TODO - is this code ever called? + $delimiter = $form_field->getFieldArg( 'is_list' ); + // first, check if it's a list + if ( array_key_exists( 'is_list', $cur_value ) && + $cur_value['is_list'] == true ) { + $cur_value_in_template = ""; + foreach ( $cur_value as $key => $val ) { + if ( $key !== "is_list" ) { + if ( $cur_value_in_template != "" ) { + $cur_value_in_template .= $delimiter . " "; + } + $cur_value_in_template .= $val; + } + } + } else { + // If it's not a list, it's probably from a checkbox or date input - + // convert the values into a string. + $cur_value_in_template = self::getStringFromPassedInArray( $cur_value, $delimiter ); + } + } elseif ( $form_field->holdsTemplate() ) { + // If this field holds an embedded template, + // and the value is not an array, it means + // there are no instances of the template - + // set the value to null to avoid getting + // whatever is currently on the page. + $cur_value_in_template = null; + } else { // value is not an array + $cur_value_in_template = $cur_value; + } + + // If we're creating the page name from a formula based on + // form values, see if the current input is part of that formula, + // and if so, substitute in the actual value. + if ( $form_submitted && $generated_page_name !== '' ) { + // This line appears to be unnecessary. + // $generated_page_name = str_replace('.', '_', $generated_page_name); + $generated_page_name = str_replace( ' ', '_', $generated_page_name ); + $escaped_input_name = str_replace( ' ', '_', $form_field->getInputName() ); + $generated_page_name = str_ireplace( "<$escaped_input_name>", $cur_value_in_template, $generated_page_name ); + // Once the substitution is done, replace underlines back + // with spaces. + $generated_page_name = str_replace( '_', ' ', $generated_page_name ); + } + + // Call hooks - unfortunately this has to be split into two + // separate calls, because of the different variable names in + // each case. + if ( $form_submitted ) { + Hooks::run( 'PageForms::CreateFormField', array( &$form_field, &$cur_value_in_template, true ) ); + } else { + if ( !empty( $cur_value ) && + ( $form_field->hasFieldArg( 'mapping template' ) || + $form_field->hasFieldArg( 'mapping property' ) || + ( $form_field->hasFieldArg( 'mapping cargo table' ) && + $form_field->hasFieldArg( 'mapping cargo field' ) ) ) || + $form_field->getUseDisplayTitle() ) { + // If the input type is "tokens', the value is not + // an array, but the delimiter still needs to be set. + if ( !is_array( $cur_value ) ) { + if ( $form_field->hasFieldArg( 'delimiter' ) ) { + $delimiter = $form_field->getFieldArg( 'delimiter' ); + } else { + $delimiter = ','; + } + } + $cur_value = $form_field->valueStringToLabels( $cur_value, $delimiter ); + } + Hooks::run( 'PageForms::CreateFormField', array( &$form_field, &$cur_value, false ) ); + } + // if this is not part of a 'multiple' template, increment the + // global tab index (used for correct tabbing) + if ( ! $form_field->hasFieldArg( 'part_of_multiple' ) ) { + $wgPageFormsTabIndex++; + } + // increment the global field number regardless + $wgPageFormsFieldNum++; + // 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. + if ( $form_field->getDefaultValue() == 'now' && + // if the date is hidden, cur_value will already be set + // to the default value + ( $cur_value == '' || $cur_value == 'now' ) ) { + $input_type = $form_field->getInputType(); + if ( $input_type == 'date' || $input_type == 'datetime' || + $input_type == 'year' || + ( $input_type == '' && $form_field->getTemplateField()->getPropertyType() == '_dat' ) ) { + $cur_value_in_template = self::getStringForCurrentTime( $input_type == 'datetime', $form_field->hasFieldArg( 'include timezone' ) ); + } + } + // 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. + if ( $form_field->getDefaultValue() == 'current user' && + // if the date is hidden, cur_value will already be set + // to the default value + ( $cur_value === '' || $cur_value == 'current user' ) ) { + + $cur_value_in_template = $wgUser->getName(); + $cur_value = $cur_value_in_template; + } + + // If all instances have been + // printed, that means we're + // now printing a "starter" + // div - set the current value + // to null, unless it's the + // default value. + // (Ideally it wouldn't get + // set at all, but that seems a + // little harder.) + if ( $tif->allInstancesPrinted() && $form_field->getDefaultValue() == null ) { + $cur_value = null; + } + + $new_text = $this->formFieldHTML( $form_field, $cur_value ); + $new_text .= $form_field->additionalHTMLForInput( $cur_value, $field_name, $tif->getTemplateName() ); + + if ( $new_text ) { + $this->wiki_page->addTemplateParam( $template_name, $tif->getInstanceNum(), $field_name, $cur_value_in_template ); + $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + } else { + $start_position = $brackets_end_loc; + } + } + + if ( $tif->allowsMultiple() && !$tif->allInstancesPrinted() ) { + $wordForYes = PFUtils::getWordForYesOrNo( true ); + if ( $form_field->getInputType() == 'checkbox' ) { + if ( strtolower( $cur_value ) == strtolower( $wordForYes ) || strtolower( $cur_value ) == 'yes' || $cur_value == '1' ) { + $cur_value = true; + } else { + $cur_value = false; + } + } + } + + if ( $tif->getDisplay() != null && ( !$tif->allowsMultiple() || !$tif->allInstancesPrinted() ) ) { + $tif->addGridValue( $field_name, $cur_value ); + } + return $placeholdFieldText; + } + + // function to handle the {{{section}}} tag + private function tagSection(&$section, &$existing_page_content, $tag_components, $source_is_page, $brackets_loc, $brackets_end_loc) { + global $wgRequest; + $section_name = trim( $tag_components[1] ); + $page_section_in_form = PFPageSection::newFromFormTag( $tag_components ); + $section_text = null; + + // Split the existing page contents into the textareas in the form. + $default_value = ""; + $section_start_loc = 0; + if ( $source_is_page && $existing_page_content !== null ) { + // For the last section of the page, there is no trailing newline in + // $existing_page_content, but the code below expects it. This code + // ensures that there is always trailing newline. T72202 + if ( substr( $existing_page_content, -1 ) !== "\n" ) { + $existing_page_content .= "\n"; + } + + $equalsSigns = str_pad( '', $page_section_in_form->getSectionLevel(), '=' ); + $searchStr = + '/^' . + preg_quote( $equalsSigns, '/' ) . + '[ ]*?' . + preg_quote( $section_name, '/' ) . + '[ ]*?' . + preg_quote( $equalsSigns, '/' ) . + '$/m'; + if ( preg_match( $searchStr, $existing_page_content, $matches, PREG_OFFSET_CAPTURE ) ) { + $section_start_loc = $matches[0][1]; + $header_text = $matches[0][0]; + $existing_page_content = str_replace( $header_text, '', $existing_page_content ); + } else { + $section_start_loc = 0; + } + $section_end_loc = -1; + + // get the position of the next template or section defined in the form + $next_section_start_loc = strpos( $section, '{{{', $brackets_end_loc ); + if ( $next_section_start_loc == false ) { + $section_end_loc = strpos( $existing_page_content, '{{', $section_start_loc ); + } else { + $next_section_end_loc = strpos( $section, '}}}', $next_section_start_loc ); + $bracketed_string_next_section = substr( $section, $next_section_start_loc + 3, $next_section_end_loc - ( $next_section_start_loc + 3 ) ); + $tag_components_next_section = PFUtils::getFormTagComponents( $bracketed_string_next_section ); + $tag_title_next_section = trim( $tag_components_next_section[0] ); + if ( $tag_title_next_section == 'section' ) { + if ( preg_match( '/(^={1,6}[ ]*?' . $tag_components_next_section[1] . '[ ]*?={1,6}\s*?$)/m', $existing_page_content, $matches, PREG_OFFSET_CAPTURE ) ) { + $section_end_loc = $matches[0][1]; + } + } + } + + if ( $section_end_loc === -1 ) { + $section_text = $existing_page_content; + $existing_page_content = ''; + } else { + $section_text = substr( $existing_page_content, $section_start_loc, $section_end_loc - $section_start_loc ); + $existing_page_content = substr( $existing_page_content, $section_end_loc ); + } + } + + // If input is from the form. + if ( ( ! $source_is_page ) && $wgRequest ) { + $text_per_section = $wgRequest->getArray( '_section' ); + $section_text = $text_per_section[trim( $section_name )]; + $this->wiki_page->addSection( $section_name, $page_section_in_form->getSectionLevel(), $section_text ); + } + + $section_text = trim( $section_text ); + + // Set input name for query string. + $input_name = '_section' . '[' . trim( $section_name ) . ']'; + $other_args = $page_section_in_form->getSectionArgs(); + $other_args['isSection'] = true; + if ( $page_section_in_form->isMandatory() ) { + $other_args['mandatory'] = true; + } + + if ( $page_section_in_form->isHidden() ) { + $form_section_text = Html::hidden( $input_name, $section_text ); + } else { + $sectionInput = new PFTextAreaInput( $input_number = null, $section_text, $input_name, ( $this->form_is_disabled || $page_section_in_form->isRestricted() ), $other_args ); + $sectionInput->addJavaScript(); + $form_section_text = $sectionInput->getHtmlText(); + } + + $section = substr_replace( $section, $form_section_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + } + + // Separate function to handle form tags + private function handleFormTags( + $parser, + $form_def, + $form_submitted, + $form_id, + $existing_page_content, + $form_text, + $is_query, + $source_is_page + ) { + global $wgRequest; + global $wgPageFormsTabIndex; // used to represent the current tab index in the form + global $wgPageFormsFieldNum; // used for setting various HTML IDs + + // first, obtain if the form is partially submitted again: + $partial_form_submitted = $wgRequest->getCheck( 'partial' ); + + $form_def = PFFormUtils::getFormDefinition( $parser, $form_def, $form_id ); + + // Turn form definition file into an array of sections, one for + // each template definition (plus the first section). + $form_def_sections = array(); + $start_position = 0; + $section_start = 0; + $this->free_text_was_included = false; + // @HACK - replace the 'free text' standard input with a + // field declaration to get it to be handled as a field. + $form_def = str_replace( 'standard input|free text', 'field|#freetext#', $form_def ); + while ( $brackets_loc = strpos( $form_def, "{{{", $start_position ) ) { + $brackets_end_loc = strpos( $form_def, "}}}", $brackets_loc ); + $bracketed_string = substr( $form_def, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) ); + $tag_components = PFUtils::getFormTagComponents( $bracketed_string ); + $tag_title = trim( $tag_components[0] ); + if ( $tag_title == 'for template' || $tag_title == 'end template' ) { + // Create a section for everything up to here + $section = substr( $form_def, $section_start, $brackets_loc - $section_start ); + $form_def_sections[] = $section; + $section_start = $brackets_loc; + } + $start_position = $brackets_loc + 1; + } // end while + $form_def_sections[] = trim( substr( $form_def, $section_start ) ); + + // Cycle through the form definition file, and possibly an + // existing article as well, finding template and field + // declarations and replacing them with form elements, either + // blank or pre-populated, as appropriate. + $template_name = null; + $template = null; + $tif = null; + // 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; + // the append is there to ensure that the original + // array doesn't get modified; is it necessary? + $section = " " . $form_def_sections[$section_num]; + + 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 ) ); + $tag_components = PFUtils::getFormTagComponents( $bracketed_string ); + $tag_title = trim( $tag_components[0] ); + // ===================================================== + // for template processing + // ===================================================== + if ( $tag_title == 'for template' ) { + // Remove template tag. + $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + + // Delegate main handling of this template to tag-handler function + $this->tagForTemplate($tif, $template, $existing_page_content, $tag_components, $template_name, $source_is_page, $partial_form_submitted); + + // We get values from the request, + // regardless of whether the the source + // is the page or a form submit, because + // even if the source is a page, values + // can still come from a query string. + $tif->setFieldValuesFromSubmit(); + + $tif->checkIfAllInstancesPrinted( $form_submitted, $source_is_page ); + + if ( !$tif->allInstancesPrinted() ) { + $this->wiki_page->addTemplate( $tif ); + } + + // ===================================================== + // end template processing + // ===================================================== + } elseif ( $tag_title == 'end template' ) { + if ( $source_is_page ) { + // Add any unhandled template fields + // in the page as hidden variables. + $form_text .= PFFormUtils::unhandledFieldsHTML( $tif ); + } + // Remove this tag from the $section variable. + $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + $template = null; + $tif = null; + // ===================================================== + // field processing + // ===================================================== + } elseif ( $tag_title == 'field' ) { + // Delegate handling of this tag to tag-handler function, to keep this function more organised + $placeholdFieldText = $this->tagField( + $tif, + $template, + $existing_page_content, + $section, + $tag_components, + $template_name, + $source_is_page, + $form_submitted, + $brackets_loc, + $brackets_end_loc + ); + if ($placeholdFieldText != null) + $placeholderFields[] = $placeholdFieldText; + + // ===================================================== + // standard input processing + // ===================================================== + } elseif ( $tag_title == 'standard input' ) { + // handle all the possible values + $input_name = $tag_components[1]; + $input_label = null; + $attr = array(); + + // if it's a query, ignore all standard inputs except run query + if ( ( $is_query && $input_name != 'run query' ) || ( !$is_query && $input_name == 'run query' ) ) { + $new_text = ""; + $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + continue; + } + // set a flag so that the standard 'form bottom' won't get displayed + $this->standardInputsIncluded = true; + // cycle through the other components + $is_checked = false; + for ( $i = 2; $i < count( $tag_components ); $i++ ) { + $component = $tag_components[$i]; + $sub_components = array_map( 'trim', explode( '=', $component ) ); + if ( count( $sub_components ) == 1 ) { + if ( $sub_components[0] == 'checked' ) { + $is_checked = true; + } + } elseif ( count( $sub_components ) == 2 ) { + switch( $sub_components[0] ) { + case 'label': + $input_label = $wgParser->recursiveTagParse( $sub_components[1] ); + break; + case 'class': + $attr['class'] = $sub_components[1]; + break; + case 'style': + $attr['style'] = Sanitizer::checkCSS( $sub_components[1] ); + break; + } + } + } + switch ($input_name) { + case 'summary': + $value = $wgRequest->getVal( 'wpSummary' ); + $new_text = PFFormUtils::summaryInputHTML( $this->form_is_disabled, $input_label, $attr, $value ); + break; + case 'minor edit': + $is_checked = $wgRequest->getCheck( 'wpMinoredit' ); + $new_text = PFFormUtils::minorEditInputHTML( $form_submitted, $this->form_is_disabled, $is_checked, $input_label, $attr ); + break; + case 'watch': + $is_checked = $wgRequest->getCheck( 'wpWatchthis' ); + $new_text = PFFormUtils::watchInputHTML( $form_submitted, $this->form_is_disabled, $is_checked, $input_label, $attr ); + break; + case 'save': + $new_text = PFFormUtils::saveButtonHTML( $this->form_is_disabled, $input_label, $attr ); + break; + case 'save and continue': + $new_text = PFFormUtils::saveAndContinueButtonHTML( $this->form_is_disabled, $input_label, $attr ); + break; + case 'preview': + $new_text = PFFormUtils::showPreviewButtonHTML( $this->form_is_disabled, $input_label, $attr ); + break; + case 'changes': + $new_text = PFFormUtils::showChangesButtonHTML( $this->form_is_disabled, $input_label, $attr ); + break; + case 'cancel': + $new_text = PFFormUtils::cancelLinkHTML( $this->form_is_disabled, $input_label, $attr ); + break; + case 'run query': + $new_text = PFFormUtils::runQueryButtonHTML( $this->form_is_disabled, $input_label, $attr ); + break; + } + $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + // ===================================================== + // for section processing + // ===================================================== + } elseif ( $tag_title == 'section' ) { + $wgPageFormsFieldNum++; + $wgPageFormsTabIndex++; + + $this->tagSection($section, $existing_page_content, $tag_components, $source_is_page, $brackets_loc, $brackets_end_loc); + // ===================================================== + // page info processing + // ===================================================== + } elseif ( $tag_title == 'info' ) { + // TODO: Generate an error message if this is included more than once + foreach ( array_slice( $tag_components, 1 ) as $component ) { + $sub_components = array_map( 'trim', explode( '=', $component, 2 ) ); + // Tag names are case-insensitive + $tag = strtolower( $sub_components[0] ); + if ( $tag == 'create title' || $tag == 'add title' ) { + // Handle this only if + // we're adding a page. + if ( !$is_query && !$this->mPageTitle->exists() ) { + $form_page_title = $sub_components[1]; + } + } elseif ( $tag == 'edit title' ) { + // Handle this only if + // we're editing a page. + if ( !$is_query && $this->mPageTitle->exists() ) { + $form_page_title = $sub_components[1]; + } + } elseif ( $tag == 'query title' ) { + // Handle this only if + // we're in 'RunQuery'. + if ( $is_query ) { + $form_page_title = $sub_components[1]; + } + } elseif ( $tag == 'partial form' ) { + $form_is_partial = true; + // replacement pages may have minimal matches... + $this->source_matches_form = true; + } elseif ( $tag == 'includeonly free text' || $tag == 'onlyinclude free text' ) { + $this->wiki_page->makeFreeTextOnlyInclude(); + } elseif ( $tag == 'query form at top' ) { + // TODO - this should be made a field of + // some non-static class that actually + // prints the form, instead of requiring + // a global variable. + global $wgPageFormsRunQueryFormAtTop; + $wgPageFormsRunQueryFormAtTop = true; + } + } + $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + // ===================================================== + // default outer level processing + // ===================================================== + } else { // Tag is not one of the allowed values - + // ignore it, other than to HTML-escape it. + $form_section_text = htmlspecialchars( substr( $section, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ) ); + $section = substr_replace( $section, $form_section_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + $start_position = $brackets_end_loc; + } // end if + } // end while + + if ( $tif && ( !$tif->allowsMultiple() || $tif->allInstancesPrinted() ) ) { + $template_text = $this->wiki_page->createTemplateCallsForTemplateName( $tif->getTemplateName() ); + // 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?)/', + preg_replace( '/\}\}/m', '}�', + preg_replace( '/\{\{/m', '�{', $template_text ) ) . + "{{{insertionpoint}}}", + $existing_page_content ); + // Otherwise, if it's a partial form, we have to add the new + // text somewhere. + } elseif ( $partial_form_submitted ) { + $existing_page_content = preg_replace( '/\}\}/m', '}�', + preg_replace( '/\{\{/m', '�{', $template_text ) ) . + "{{{insertionpoint}}}" . $existing_page_content; + } + } + + $multipleTemplateHTML = ''; + if ( $tif && $tif->getLabel() != null ) { + $fieldsetStartHTML = "<fieldset>\n" . Html::element( 'legend', null, $tif->getLabel() ) . "\n"; + if ( !$tif->allowsMultiple() ) { + $form_text .= $fieldsetStartHTML; + } elseif ( $tif->allowsMultiple() && $tif->getInstanceNum() == 0 ) { + $multipleTemplateHTML .= $fieldsetStartHTML; + } + } + if ( $tif && $tif->allowsMultiple() ) { + if ( $tif->getDisplay() == 'spreadsheet' ) { + if ( $tif->allInstancesPrinted() ) { + $multipleTemplateHTML .= $this->spreadsheetHTML( $tif ); + // For spreadsheets, this needs + // to be specially inserted. + $multipleTemplateHTML .= "</fieldset>\n"; + } + } else { + if ( $tif->getDisplay() == 'table' ) { + $section = $this->tableHTML( $tif, $tif->getInstanceNum() ); + } + if ( $tif->getInstanceNum() == 0 ) { + $multipleTemplateHTML .= $this->multipleTemplateStartHTML( $tif ); + } + if ( ! $tif->allInstancesPrinted() ) { + $multipleTemplateHTML .= $this->multipleTemplateInstanceHTML( $tif, $section ); + } else { + $multipleTemplateHTML .= $this->multipleTemplateEndHTML( $tif, $section ); + } + } + $placeholder = $tif->getPlaceholder(); + if ( $placeholder == null ) { + // The normal process. + $form_text .= $multipleTemplateHTML; + } else { + // The template text won't be appended + // at the end of the template like for + // usual multiple template forms. + // The HTML text will instead be stored in + // the $multipleTemplateHTML 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. + // We replace the HTML into the current + // placeholder tag, but also add another + // placeholder tag, to keep track of it. + $multipleTemplateHTML .= self::makePlaceholderInFormHTML( $placeholder ); + $form_text = str_replace( self::makePlaceholderInFormHTML( $placeholder ), $multipleTemplateHTML, $form_text ); + } + if ( ! $tif->allInstancesPrinted() ) { + // This will cause the section to be + // re-parsed on the next go. + $section_num--; + $tif->incrementInstanceNum(); + } + } elseif ( $tif && $tif->getDisplay() == 'table' ) { + $form_text .= $this->tableHTML( $tif, 0 ); + } elseif ( $tif && !$tif->allowsMultiple() && $tif->getLabel() != null ) { + $form_text .= $section . "\n</fieldset>"; + } else { + $form_text .= $section; + } + } // 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 @<insertHTML>@ tags from the generated + // HTML form. + $form_text = str_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 ( ! $this->free_text_was_included ) { + $form_text .= Html::hidden( 'pf_free_text', '!free_text!' ); + } + // Get free text, and add to page data, as well as retroactively + // inserting it into the form. + return $form_text; + } + /** * This function is the real heart of the entire Page Forms - * extension. It handles two main actions: (1) displaying a form on the - * screen, given a form definition and possibly page contents (if an - * existing page is being edited); and (2) creating actual page - * contents, if the form was already submitted by the user. + * extension. It relies mostly on the above private functions. + * It handles two main actions: + * (1) displaying a form on the page, + * given a form definition and possibly page contents (if an + * existing page is being edited); + * (2) creating actual page contents, + * if the form was already submitted by the user. * * It also does some related tasks, like figuring out the page name (if * only a page formula exists). @@ -669,10 +1434,10 @@ global $wgPageFormsFieldNum; // used for setting various HTML IDs // Initialize some variables. - $wiki_page = new PFWikiPage(); + $this->wiki_page = new PFWikiPage(); $wgPageFormsTabIndex = 0; $wgPageFormsFieldNum = 0; - $source_page_matches_this_form = false; + $this->source_matches_form = false; $form_page_title = null; $generated_page_name = $page_name_formula; // $form_is_partial is true if: @@ -753,7 +1518,7 @@ } $form_text = ""; if ( $is_query || $userCanEditPage ) { - $form_is_disabled = false; + $this->form_is_disabled = false; // Show "Your IP address will be recorded" warning if // user is anonymous, and it's not a query. if ( $wgUser->isAnon() && ! $is_query ) { @@ -766,7 +1531,7 @@ $form_text .= Html::rawElement( 'div', array( 'id' => 'mw-anon-edit-warning', 'class' => 'warningbox' ), $anonEditWarning ); } } else { - $form_is_disabled = true; + $this->form_is_disabled = true; $wgOut->setPageTitle( wfMessage( 'badaccess' )->text() ); $wgOut->addWikiText( $wgOut->formatPermissionsErrorMessage( $permissionErrors, 'edit' ) ); $wgOut->addHTML( "\n<hr />\n" ); @@ -783,681 +1548,17 @@ // is set. $wgParser->clearState(); - $form_def = PFFormUtils::getFormDefinition( $wgParser, $form_def, $form_id ); - - // Turn form definition file into an array of sections, one for - // each template definition (plus the first section). - $form_def_sections = array(); - $start_position = 0; - $section_start = 0; - $free_text_was_included = false; - $preloaded_free_text = null; - // @HACK - replace the 'free text' standard input with a - // field declaration to get it to be handled as a field. - $form_def = str_replace( 'standard input|free text', 'field|#freetext#', $form_def ); - while ( $brackets_loc = strpos( $form_def, "{{{", $start_position ) ) { - $brackets_end_loc = strpos( $form_def, "}}}", $brackets_loc ); - $bracketed_string = substr( $form_def, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) ); - $tag_components = PFUtils::getFormTagComponents( $bracketed_string ); - $tag_title = trim( $tag_components[0] ); - if ( $tag_title == 'for template' || $tag_title == 'end template' ) { - // Create a section for everything up to here - $section = substr( $form_def, $section_start, $brackets_loc - $section_start ); - $form_def_sections[] = $section; - $section_start = $brackets_loc; - } - $start_position = $brackets_loc + 1; - } // end while - $form_def_sections[] = trim( substr( $form_def, $section_start ) ); - - // Cycle through the form definition file, and possibly an - // existing article as well, finding template and field - // declarations and replacing them with form elements, either - // blank or pre-populated, as appropriate. - $template_name = null; - $template = null; - $tif = null; - // 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; - // the append is there to ensure that the original - // array doesn't get modified; is it necessary? - $section = " " . $form_def_sections[$section_num]; - - 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 ) ); - $tag_components = PFUtils::getFormTagComponents( $bracketed_string ); - $tag_title = trim( $tag_components[0] ); - // ===================================================== - // for template processing - // ===================================================== - if ( $tag_title == 'for template' ) { - if ( $tif ) { - $previous_template_name = $tif->getTemplateName(); - } else { - $previous_template_name = ''; - } - $template_name = str_replace( '_', ' ', $tag_components[1] ); - $is_new_template = ( $template_name != $previous_template_name ); - if ( $is_new_template ) { - $template = PFTemplate::newFromName( $template_name ); - $tif = PFTemplateInForm::newFromFormTag( $tag_components ); - } - // Remove template tag. - $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - // 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. - if ( $source_is_page || $partial_form_submitted ) { - $tif->setPageRelatedInfo( $existing_page_content ); - // Get the first instance of - // this template on the page - // being edited, even if there - // are more. - if ( $tif->pageCallsThisTemplate() ) { - $tif->setFieldValuesFromPage( $existing_page_content ); - $existing_template_text = $tif->getFullTextInPage(); - // Now remove this template from the text being edited. - // If this is a partial form, establish a new insertion point. - if ( $existing_page_content && $partial_form_submitted ) { - // If something already exists, set the new insertion point - // to its position; otherwise just let it lie. - if ( strpos( $existing_page_content, $existing_template_text ) !== false ) { - $existing_page_content = str_replace( "\n" . '{{{insertionpoint}}}', '', $existing_page_content ); - $existing_page_content = str_replace( $existing_template_text, '{{{insertionpoint}}}', $existing_page_content ); - } - } else { - $existing_page_content = $this->strReplaceFirst( $existing_template_text, '', $existing_page_content ); - } - // If we've found a match in the source - // page, there's a good chance that this - // page was created with this form - note - // that, so we don't send the user a warning. - $source_page_matches_this_form = true; - } - } - - // We get values from the request, - // regardless of whether the the source - // is the page or a form submit, because - // even if the source is a page, values - // can still come from a query string. - $tif->setFieldValuesFromSubmit(); - - $tif->checkIfAllInstancesPrinted( $form_submitted, $source_is_page ); - - if ( !$tif->allInstancesPrinted() ) { - $wiki_page->addTemplate( $tif ); - } - - // ===================================================== - // end template processing - // ===================================================== - } elseif ( $tag_title == 'end template' ) { - if ( $source_is_page ) { - // Add any unhandled template fields - // in the page as hidden variables. - $form_text .= PFFormUtils::unhandledFieldsHTML( $tif ); - } - // Remove this tag from the $section variable. - $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - $template = null; - $tif = null; - // ===================================================== - // field processing - // ===================================================== - } elseif ( $tag_title == 'field' ) { - - // If the template is null, that (hopefully) - // means we're handling the free text field. - // Make the template a dummy variable. - if ( $tif == null ) { - $template = new PFTemplate( null, array() ); - $tif = new PFTemplateInForm(); - } - // We get the field name both here - // and in the PFFormField constructor, - // because PFFormField isn't equipped - // to deal with the #freetext# hack, - // among others. - $field_name = trim( $tag_components[1] ); - $form_field = PFFormField::newFromFormFieldTag( $tag_components, $template, $tif, $form_is_disabled ); - // For special displays, add in the - // form fields, so we know the data - // structure. - if ( ( $tif->getDisplay() == 'table' && ( !$tif->allowsMultiple() || $tif->getInstanceNum() == 0 ) ) || - ( $tif->getDisplay() == 'spreadsheet' && $tif->allowsMultiple() && $tif->getInstanceNum() == 0 ) ) { - $tif->addField( $form_field ); - } - $cur_value = $form_field->getCurrentValue( $tif->getValuesFromSubmit(), $form_submitted, $source_is_page, $tif->allInstancesPrinted() ); - if ( $form_field->holdsTemplate() ) { - $placeholderFields[] = self::placeholderFormat( $tif->getTemplateName(), $field_name ); - } - - // 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 && ( $tif->getFullTextInPage() != '' && !$form_submitted ) ) { - if ( $tif->hasValueFromPageForField( $field_name ) ) { - // Get value, and remove it, - // so that at the end we - // can have a list of all - // the fields that weren't - // handled by the form. - $cur_value = $tif->getAndRemoveValueFromPageForField( $field_name ); - - // 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 ( $form_field->holdsTemplate() ) { - $existing_page_content .= $cur_value; - } - } elseif ( isset( $cur_value ) && !empty( $cur_value ) ) { - // Do nothing. - } else { - $cur_value = ''; - } - } - - // Handle the free text field. - if ( $field_name == '#freetext#' ) { - // If there was no preloading, this will just be blank. - $preloaded_free_text = $cur_value; - // Add placeholders for the free text in both the form and - // the page, using <free_text> tags - once all the free text - // is known (at the end), it will get substituted in. - if ( $form_field->isHidden() ) { - $new_text = Html::hidden( 'pf_free_text', '!free_text!' ); - } else { - $wgPageFormsTabIndex++; - $wgPageFormsFieldNum++; - if ( $cur_value === '' || is_null( $cur_value ) ) { - $default_value = '!free_text!'; - } else { - $default_value = $cur_value; - } - $freeTextInput = new PFTextAreaInput( $input_number = null, $default_value, 'pf_free_text', ( $form_is_disabled || $form_field->isRestricted() ), $form_field->getFieldArgs() ); - $freeTextInput->addJavaScript(); - $new_text = $freeTextInput->getHtmlText(); - if ( $form_field->hasFieldArg( 'edittools' ) ) { - // borrowed from EditPage::showEditTools() - $edittools_text = $wgParser->recursiveTagParse( wfMessage( 'edittools', array( 'content' ) )->text() ); - - $new_text .= <<<END - <div class="mw-editTools"> - $edittools_text - </div> - -END; - } - } - $free_text_was_included = true; - $wiki_page->addFreeTextSection(); - } - - if ( $tif->getTemplateName() === '' || $field_name == '#freetext#' ) { - $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - } else { - if ( is_array( $cur_value ) ) { - // @TODO - is this code ever called? - $delimiter = $form_field->getFieldArg( 'is_list' ); - // first, check if it's a list - if ( array_key_exists( 'is_list', $cur_value ) && - $cur_value['is_list'] == true ) { - $cur_value_in_template = ""; - foreach ( $cur_value as $key => $val ) { - if ( $key !== "is_list" ) { - if ( $cur_value_in_template != "" ) { - $cur_value_in_template .= $delimiter . " "; - } - $cur_value_in_template .= $val; - } - } - } else { - // If it's not a list, it's probably from a checkbox or date input - - // convert the values into a string. - $cur_value_in_template = self::getStringFromPassedInArray( $cur_value, $delimiter ); - } - } elseif ( $form_field->holdsTemplate() ) { - // If this field holds an embedded template, - // and the value is not an array, it means - // there are no instances of the template - - // set the value to null to avoid getting - // whatever is currently on the page. - $cur_value_in_template = null; - } else { // value is not an array - $cur_value_in_template = $cur_value; - } - - // If we're creating the page name from a formula based on - // form values, see if the current input is part of that formula, - // and if so, substitute in the actual value. - if ( $form_submitted && $generated_page_name !== '' ) { - // This line appears to be unnecessary. - // $generated_page_name = str_replace('.', '_', $generated_page_name); - $generated_page_name = str_replace( ' ', '_', $generated_page_name ); - $escaped_input_name = str_replace( ' ', '_', $form_field->getInputName() ); - $generated_page_name = str_ireplace( "<$escaped_input_name>", $cur_value_in_template, $generated_page_name ); - // Once the substitution is done, replace underlines back - // with spaces. - $generated_page_name = str_replace( '_', ' ', $generated_page_name ); - } - - // Call hooks - unfortunately this has to be split into two - // separate calls, because of the different variable names in - // each case. - if ( $form_submitted ) { - Hooks::run( 'PageForms::CreateFormField', array( &$form_field, &$cur_value_in_template, true ) ); - } else { - if ( !empty( $cur_value ) && - ( $form_field->hasFieldArg( 'mapping template' ) || - $form_field->hasFieldArg( 'mapping property' ) || - ( $form_field->hasFieldArg( 'mapping cargo table' ) && - $form_field->hasFieldArg( 'mapping cargo field' ) ) ) || - $form_field->getUseDisplayTitle() ) { - // If the input type is "tokens', the value is not - // an array, but the delimiter still needs to be set. - if ( !is_array( $cur_value ) ) { - if ( $form_field->hasFieldArg( 'delimiter' ) ) { - $delimiter = $form_field->getFieldArg( 'delimiter' ); - } else { - $delimiter = ','; - } - } - $cur_value = $form_field->valueStringToLabels( $cur_value, $delimiter ); - } - Hooks::run( 'PageForms::CreateFormField', array( &$form_field, &$cur_value, false ) ); - } - // if this is not part of a 'multiple' template, increment the - // global tab index (used for correct tabbing) - if ( ! $form_field->hasFieldArg( 'part_of_multiple' ) ) { - $wgPageFormsTabIndex++; - } - // increment the global field number regardless - $wgPageFormsFieldNum++; - // 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. - if ( $form_field->getDefaultValue() == 'now' && - // if the date is hidden, cur_value will already be set - // to the default value - ( $cur_value == '' || $cur_value == 'now' ) ) { - $input_type = $form_field->getInputType(); - if ( $input_type == 'date' || $input_type == 'datetime' || - $input_type == 'year' || - ( $input_type == '' && $form_field->getTemplateField()->getPropertyType() == '_dat' ) ) { - $cur_value_in_template = self::getStringForCurrentTime( $input_type == 'datetime', $form_field->hasFieldArg( 'include timezone' ) ); - } - } - // 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. - if ( $form_field->getDefaultValue() == 'current user' && - // if the date is hidden, cur_value will already be set - // to the default value - ( $cur_value === '' || $cur_value == 'current user' ) ) { - - $cur_value_in_template = $wgUser->getName(); - $cur_value = $cur_value_in_template; - } - - // If all instances have been - // printed, that means we're - // now printing a "starter" - // div - set the current value - // to null, unless it's the - // default value. - // (Ideally it wouldn't get - // set at all, but that seems a - // little harder.) - if ( $tif->allInstancesPrinted() && $form_field->getDefaultValue() == null ) { - $cur_value = null; - } - - $new_text = $this->formFieldHTML( $form_field, $cur_value ); - $new_text .= $form_field->additionalHTMLForInput( $cur_value, $field_name, $tif->getTemplateName() ); - - if ( $new_text ) { - $wiki_page->addTemplateParam( $template_name, $tif->getInstanceNum(), $field_name, $cur_value_in_template ); - $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - } else { - $start_position = $brackets_end_loc; - } - } - - if ( $tif->allowsMultiple() && !$tif->allInstancesPrinted() ) { - $wordForYes = PFUtils::getWordForYesOrNo( true ); - if ( $form_field->getInputType() == 'checkbox' ) { - if ( strtolower( $cur_value ) == strtolower( $wordForYes ) || strtolower( $cur_value ) == 'yes' || $cur_value == '1' ) { - $cur_value = true; - } else { - $cur_value = false; - } - } - } - - if ( $tif->getDisplay() != null && ( !$tif->allowsMultiple() || !$tif->allInstancesPrinted() ) ) { - $tif->addGridValue( $field_name, $cur_value ); - } - - // ===================================================== - // standard input processing - // ===================================================== - } elseif ( $tag_title == 'standard input' ) { - // handle all the possible values - $input_name = $tag_components[1]; - $input_label = null; - $attr = array(); - - // if it's a query, ignore all standard inputs except run query - if ( ( $is_query && $input_name != 'run query' ) || ( !$is_query && $input_name == 'run query' ) ) { - $new_text = ""; - $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - continue; - } - // set a flag so that the standard 'form bottom' won't get displayed - $this->standardInputsIncluded = true; - // cycle through the other components - $is_checked = false; - for ( $i = 2; $i < count( $tag_components ); $i++ ) { - $component = $tag_components[$i]; - $sub_components = array_map( 'trim', explode( '=', $component ) ); - if ( count( $sub_components ) == 1 ) { - if ( $sub_components[0] == 'checked' ) { - $is_checked = true; - } - } elseif ( count( $sub_components ) == 2 ) { - switch( $sub_components[0] ) { - case 'label': - $input_label = $wgParser->recursiveTagParse( $sub_components[1] ); - break; - case 'class': - $attr['class'] = $sub_components[1]; - break; - case 'style': - $attr['style'] = Sanitizer::checkCSS( $sub_components[1] ); - break; - } - } - } - if ( $input_name == 'summary' ) { - $value = $wgRequest->getVal( 'wpSummary' ); - $new_text = PFFormUtils::summaryInputHTML( $form_is_disabled, $input_label, $attr, $value ); - } elseif ( $input_name == 'minor edit' ) { - $is_checked = $wgRequest->getCheck( 'wpMinoredit' ); - $new_text = PFFormUtils::minorEditInputHTML( $form_submitted, $form_is_disabled, $is_checked, $input_label, $attr ); - } elseif ( $input_name == 'watch' ) { - $is_checked = $wgRequest->getCheck( 'wpWatchthis' ); - $new_text = PFFormUtils::watchInputHTML( $form_submitted, $form_is_disabled, $is_checked, $input_label, $attr ); - } elseif ( $input_name == 'save' ) { - $new_text = PFFormUtils::saveButtonHTML( $form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'save and continue' ) { - $new_text = PFFormUtils::saveAndContinueButtonHTML( $form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'preview' ) { - $new_text = PFFormUtils::showPreviewButtonHTML( $form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'changes' ) { - $new_text = PFFormUtils::showChangesButtonHTML( $form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'cancel' ) { - $new_text = PFFormUtils::cancelLinkHTML( $form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'run query' ) { - $new_text = PFFormUtils::runQueryButtonHTML( $form_is_disabled, $input_label, $attr ); - } - $section = substr_replace( $section, $new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - // ===================================================== - // for section processing - // ===================================================== - } elseif ( $tag_title == 'section' ) { - $wgPageFormsFieldNum++; - $wgPageFormsTabIndex++; - - $section_name = trim( $tag_components[1] ); - $page_section_in_form = PFPageSection::newFromFormTag( $tag_components ); - $section_text = null; - - // Split the existing page contents into the textareas in the form. - $default_value = ""; - $section_start_loc = 0; - if ( $source_is_page && $existing_page_content !== null ) { - // For the last section of the page, there is no trailing newline in - // $existing_page_content, but the code below expects it. This code - // ensures that there is always trailing newline. T72202 - if ( substr( $existing_page_content, -1 ) !== "\n" ) { - $existing_page_content .= "\n"; - } - - $equalsSigns = str_pad( '', $page_section_in_form->getSectionLevel(), '=' ); - $searchStr = - '/^' . - preg_quote( $equalsSigns, '/' ) . - '[ ]*?' . - preg_quote( $section_name, '/' ) . - '[ ]*?' . - preg_quote( $equalsSigns, '/' ) . - '$/m'; - if ( preg_match( $searchStr, $existing_page_content, $matches, PREG_OFFSET_CAPTURE ) ) { - $section_start_loc = $matches[0][1]; - $header_text = $matches[0][0]; - $existing_page_content = str_replace( $header_text, '', $existing_page_content ); - } else { - $section_start_loc = 0; - } - $section_end_loc = -1; - - // get the position of the next template or section defined in the form - $next_section_start_loc = strpos( $section, '{{{', $brackets_end_loc ); - if ( $next_section_start_loc == false ) { - $section_end_loc = strpos( $existing_page_content, '{{', $section_start_loc ); - } else { - $next_section_end_loc = strpos( $section, '}}}', $next_section_start_loc ); - $bracketed_string_next_section = substr( $section, $next_section_start_loc + 3, $next_section_end_loc - ( $next_section_start_loc + 3 ) ); - $tag_components_next_section = PFUtils::getFormTagComponents( $bracketed_string_next_section ); - $tag_title_next_section = trim( $tag_components_next_section[0] ); - if ( $tag_title_next_section == 'section' ) { - if ( preg_match( '/(^={1,6}[ ]*?' . $tag_components_next_section[1] . '[ ]*?={1,6}\s*?$)/m', $existing_page_content, $matches, PREG_OFFSET_CAPTURE ) ) { - $section_end_loc = $matches[0][1]; - } - } - } - - if ( $section_end_loc === -1 ) { - $section_text = $existing_page_content; - $existing_page_content = ''; - } else { - $section_text = substr( $existing_page_content, $section_start_loc, $section_end_loc - $section_start_loc ); - $existing_page_content = substr( $existing_page_content, $section_end_loc ); - } - } - - // If input is from the form. - if ( ( ! $source_is_page ) && $wgRequest ) { - $text_per_section = $wgRequest->getArray( '_section' ); - $section_text = $text_per_section[trim( $section_name )]; - $wiki_page->addSection( $section_name, $page_section_in_form->getSectionLevel(), $section_text ); - } - - $section_text = trim( $section_text ); - - // Set input name for query string. - $input_name = '_section' . '[' . trim( $section_name ) . ']'; - $other_args = $page_section_in_form->getSectionArgs(); - $other_args['isSection'] = true; - if ( $page_section_in_form->isMandatory() ) { - $other_args['mandatory'] = true; - } - - if ( $page_section_in_form->isHidden() ) { - $form_section_text = Html::hidden( $input_name, $section_text ); - } else { - $sectionInput = new PFTextAreaInput( $input_number = null, $section_text, $input_name, ( $form_is_disabled || $page_section_in_form->isRestricted() ), $other_args ); - $sectionInput->addJavaScript(); - $form_section_text = $sectionInput->getHtmlText(); - } - - $section = substr_replace( $section, $form_section_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - // ===================================================== - // page info processing - // ===================================================== - } elseif ( $tag_title == 'info' ) { - // TODO: Generate an error message if this is included more than once - foreach ( array_slice( $tag_components, 1 ) as $component ) { - $sub_components = array_map( 'trim', explode( '=', $component, 2 ) ); - // Tag names are case-insensitive - $tag = strtolower( $sub_components[0] ); - if ( $tag == 'create title' || $tag == 'add title' ) { - // Handle this only if - // we're adding a page. - if ( !$is_query && !$this->mPageTitle->exists() ) { - $form_page_title = $sub_components[1]; - } - } elseif ( $tag == 'edit title' ) { - // Handle this only if - // we're editing a page. - if ( !$is_query && $this->mPageTitle->exists() ) { - $form_page_title = $sub_components[1]; - } - } elseif ( $tag == 'query title' ) { - // Handle this only if - // we're in 'RunQuery'. - if ( $is_query ) { - $form_page_title = $sub_components[1]; - } - } elseif ( $tag == 'partial form' ) { - $form_is_partial = true; - // replacement pages may have minimal matches... - $source_page_matches_this_form = true; - } elseif ( $tag == 'includeonly free text' || $tag == 'onlyinclude free text' ) { - $wiki_page->makeFreeTextOnlyInclude(); - } elseif ( $tag == 'query form at top' ) { - // TODO - this should be made a field of - // some non-static class that actually - // prints the form, instead of requiring - // a global variable. - global $wgPageFormsRunQueryFormAtTop; - $wgPageFormsRunQueryFormAtTop = true; - } - } - $section = substr_replace( $section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - // ===================================================== - // default outer level processing - // ===================================================== - } else { // Tag is not one of the allowed values - - // ignore it, other than to HTML-escape it. - $form_section_text = htmlspecialchars( substr( $section, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ) ); - $section = substr_replace( $section, $form_section_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - $start_position = $brackets_end_loc; - } // end if - } // end while - - if ( $tif && ( !$tif->allowsMultiple() || $tif->allInstancesPrinted() ) ) { - $template_text = $wiki_page->createTemplateCallsForTemplateName( $tif->getTemplateName() ); - // 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?)/', - preg_replace( '/\}\}/m', '}�', - preg_replace( '/\{\{/m', '�{', $template_text ) ) . - "{{{insertionpoint}}}", - $existing_page_content ); - // Otherwise, if it's a partial form, we have to add the new - // text somewhere. - } elseif ( $partial_form_submitted ) { - $existing_page_content = preg_replace( '/\}\}/m', '}�', - preg_replace( '/\{\{/m', '�{', $template_text ) ) . - "{{{insertionpoint}}}" . $existing_page_content; - } - } - - $multipleTemplateHTML = ''; - if ( $tif && $tif->getLabel() != null ) { - $fieldsetStartHTML = "<fieldset>\n" . Html::element( 'legend', null, $tif->getLabel() ) . "\n"; - if ( !$tif->allowsMultiple() ) { - $form_text .= $fieldsetStartHTML; - } elseif ( $tif->allowsMultiple() && $tif->getInstanceNum() == 0 ) { - $multipleTemplateHTML .= $fieldsetStartHTML; - } - } - if ( $tif && $tif->allowsMultiple() ) { - if ( $tif->getDisplay() == 'spreadsheet' ) { - if ( $tif->allInstancesPrinted() ) { - $multipleTemplateHTML .= $this->spreadsheetHTML( $tif ); - // For spreadsheets, this needs - // to be specially inserted. - $multipleTemplateHTML .= "</fieldset>\n"; - } - } else { - if ( $tif->getDisplay() == 'table' ) { - $section = $this->tableHTML( $tif, $tif->getInstanceNum() ); - } - if ( $tif->getInstanceNum() == 0 ) { - $multipleTemplateHTML .= $this->multipleTemplateStartHTML( $tif ); - } - if ( ! $tif->allInstancesPrinted() ) { - $multipleTemplateHTML .= $this->multipleTemplateInstanceHTML( $tif, $form_is_disabled, $section ); - } else { - $multipleTemplateHTML .= $this->multipleTemplateEndHTML( $tif, $form_is_disabled, $section ); - } - } - $placeholder = $tif->getPlaceholder(); - if ( $placeholder == null ) { - // The normal process. - $form_text .= $multipleTemplateHTML; - } else { - // The template text won't be appended - // at the end of the template like for - // usual multiple template forms. - // The HTML text will instead be stored in - // the $multipleTemplateHTML 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. - // We replace the HTML into the current - // placeholder tag, but also add another - // placeholder tag, to keep track of it. - $multipleTemplateHTML .= self::makePlaceholderInFormHTML( $placeholder ); - $form_text = str_replace( self::makePlaceholderInFormHTML( $placeholder ), $multipleTemplateHTML, $form_text ); - } - if ( ! $tif->allInstancesPrinted() ) { - // This will cause the section to be - // re-parsed on the next go. - $section_num--; - $tif->incrementInstanceNum(); - } - } elseif ( $tif && $tif->getDisplay() == 'table' ) { - $form_text .= $this->tableHTML( $tif, 0 ); - } elseif ( $tif && !$tif->allowsMultiple() && $tif->getLabel() != null ) { - $form_text .= $section . "\n</fieldset>"; - } else { - $form_text .= $section; - } - } // 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 @<insertHTML>@ tags from the generated - // HTML form. - $form_text = str_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 ) { - $form_text .= Html::hidden( 'pf_free_text', '!free_text!' ); - } - // Get free text, and add to page data, as well as retroactively - // inserting it into the form. + // Delegate the handling of form tags to a different function: + $form_text = $this->handleFormTags( + $wgParser, + $form_def, + $form_submitted, + $form_id, + $existing_page_content, + $form_text, + $is_query, + $source_is_page + ); // If $form_is_partial is true then either: // (a) we're processing a replacement (param 'partial' == 1) @@ -1481,16 +1582,16 @@ // or get it from a form submission } elseif ( $wgRequest->getCheck( 'pf_free_text' ) ) { $free_text = $wgRequest->getVal( 'pf_free_text' ); - if ( ! $free_text_was_included ) { - $wiki_page->addFreeTextSection(); + if ( ! $this->free_text_was_included ) { + $this->wiki_page->addFreeTextSection(); } - } elseif ( $preloaded_free_text != null ) { - $free_text = $preloaded_free_text; + } elseif ( $this->preloaded_free_text != null ) { + $free_text = $this->preloaded_free_text; } else { $free_text = null; } - if ( $wiki_page->freeTextOnlyInclude() ) { + if ( $this->wiki_page->freeTextOnlyInclude() ) { $free_text = str_replace( "<onlyinclude>", '', $free_text ); $free_text = str_replace( "</onlyinclude>", '', $free_text ); $free_text = trim( $free_text ); @@ -1505,8 +1606,8 @@ // text. // The page text needs to be created whether or not the form // was submitted, in case this is called from #formredlink. - $wiki_page->setFreeText( $free_text ); - $page_text = $wiki_page->createPageText(); + $this->wiki_page->setFreeText( $free_text ); + $page_text = $this->wiki_page->createPageText(); // Also substitute the free text into the form. $escaped_free_text = Sanitizer::safeEncodeAttribute( $free_text ); @@ -1516,7 +1617,7 @@ // page appears to not have been created with this form. if ( !$is_query && is_null( $page_name_formula ) && $this->mPageTitle->exists() && $existing_page_content !== '' - && !$source_page_matches_this_form ) { + && !$this->source_matches_form ) { $form_text = "\t" . '<div class="warningbox">' . wfMessage( 'pf_formedit_formwarning', $page_name )->parse() . "</div>\n<br clear=\"both\" />\n" . $form_text; @@ -1525,9 +1626,9 @@ // Add form bottom, if no custom "standard inputs" have been defined. if ( !$this->standardInputsIncluded ) { if ( $is_query ) { - $form_text .= PFFormUtils::queryFormBottom( $form_is_disabled ); + $form_text .= PFFormUtils::queryFormBottom( $this->form_is_disabled ); } else { - $form_text .= PFFormUtils::formBottom( $form_submitted, $form_is_disabled ); + $form_text .= PFFormUtils::formBottom( $form_submitted, $this->form_is_disabled ); } } -- To view, visit https://gerrit.wikimedia.org/r/358555 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I1be3f96bb42701a18958613d54c94ab328ddd2ab Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/PageForms Gerrit-Branch: master Gerrit-Owner: Joeytje50 <joeytj...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits