Joeytje50 has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/360339 )
Change subject: Step three: split out several processing functions ...................................................................... Step three: split out several processing functions split out all tags from the possible tags within a pageform. This reduces the huge function that contained them all, and creates a clearer structure in the function. Change-Id: I3ec87e0ca1622fd4dc0eb3b57cc45dba8711abfa --- M includes/PF_FormPrinter.php 1 file changed, 508 insertions(+), 478 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/PageForms refs/changes/39/360339/1 diff --git a/includes/PF_FormPrinter.php b/includes/PF_FormPrinter.php index b343882..f83cbd6 100644 --- a/includes/PF_FormPrinter.php +++ b/includes/PF_FormPrinter.php @@ -46,6 +46,9 @@ private $form_submitted; private $is_query; private $form_is_partial; + // keep track of the position of brackets within tag processing + private $brackets_loc; + private $brackets_end_loc; public function __construct() { global $wgPageFormsDisableOutsideServices; @@ -669,6 +672,493 @@ return ''; } + // handles {{{for template}}} + private function tagForTemplate() { + if ( $this->tif ) { + $previous_template_name = $this->tif->getTemplateName(); + } else { + $previous_template_name = ''; + } + $this->template_name = str_replace( '_', ' ', $this->tag_components[1] ); + $is_new_template = ( $this->template_name != $previous_template_name ); + if ( $is_new_template ) { + $this->template = PFTemplate::newFromName( $this->template_name ); + $this->tif = PFTemplateInForm::newFromFormTag( $this->tag_components ); + } + // Remove template tag. + $this->section = substr_replace( $this->section, '', $this->brackets_loc, $this->brackets_end_loc + 3 - $this->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 ( $this->source_is_page || $this->partial_form_submitted ) { + $this->tif->setPageRelatedInfo( $this->existing_page_content ); + // Get the first instance of this template on the page + // being edited, even if there are more. + if ( $this->tif->pageCallsThisTemplate() ) { + $this->tif->setFieldValuesFromPage( $this->existing_page_content ); + $existing_template_text = $this->tif->getFullTextInPage(); + // Now remove this template from the text being edited. + // If this is a partial form, establish a new insertion point. + if ( $this->existing_page_content && $this->partial_form_submitted ) { + // If something already exists, set the new insertion point + // to its position; otherwise just let it lie. + if ( strpos( $this->existing_page_content, $existing_template_text ) !== false ) { + $this->existing_page_content = str_replace( "\n" . '{{{insertionpoint}}}', '', $this->existing_page_content ); + $this->existing_page_content = str_replace( $existing_template_text, '{{{insertionpoint}}}', $this->existing_page_content ); + } + } else { + $this->existing_page_content = $this->strReplaceFirst( $existing_template_text, '', $this->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_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. + $this->tif->setFieldValuesFromSubmit(); + + $this->tif->checkIfAllInstancesPrinted( $this->form_submitted, $this->source_is_page ); + + if ( !$this->tif->allInstancesPrinted() ) { + $this->wiki_page->addTemplate( $this->tif ); + } + } + + // handles {{{end template}}} + private function tagEndTemplate() { + if ( $this->source_is_page ) { + // Add any unhandled template fields + // in the page as hidden variables. + $this->form_text .= PFFormUtils::unhandledFieldsHTML( $this->tif ); + } + // Remove this tag from the $this->section variable. + $this->section = substr_replace( $this->section, '', $this->brackets_loc, $this->brackets_end_loc + 3 - $this->brackets_loc ); + $this->template = null; + $this->tif = null; + } + + // handles {{{field}}} + private function tagField() { + global $wgPageFormsTabIndex; // used to represent the current tab index in the form + global $wgPageFormsFieldNum; // used for setting various HTML IDs + // If the template is null, that (hopefully) means we're handling the free text field. + // Make the template a dummy variable. + if ( $this->tif == null ) { + $this->template = new PFTemplate( null, array() ); + $this->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( $this->tag_components[1] ); + $form_field = PFFormField::newFromFormFieldTag( $this->tag_components, $this->template, $this->tif, $this->form_is_disabled ); + // For special displays, add in the form fields, so we know the data structure. + if ( ( $this->tif->getDisplay() == 'table' && ( !$this->tif->allowsMultiple() || $this->tif->getInstanceNum() == 0 ) ) || + ( $this->tif->getDisplay() == 'spreadsheet' && $this->tif->allowsMultiple() && $this->tif->getInstanceNum() == 0 ) ) { + $this->tif->addField( $form_field ); + } + $cur_value = $form_field->getCurrentValue( $this->tif->getValuesFromSubmit(), $this->form_submitted, $this->source_is_page, $this->tif->allInstancesPrinted() ); + if ( $form_field->holdsTemplate() ) { + $this->placeholderFields[] = self::placeholderFormat( $this->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 ( $this->source_is_page && ( $this->tif->getFullTextInPage() != '' && !$this->form_submitted ) ) { + if ( $this->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 = $this->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() ) { + $this->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() ) { + $this->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(); + $this->new_text = $freeTextInput->getHtmlText(); + if ( $form_field->hasFieldArg( 'edittools' ) ) { + // borrowed from EditPage::showEditTools() + $edittools_text = $wgParser->recursiveTagParse( wfMessage( 'edittools', array( 'content' ) )->text() ); + + $this->new_text .= "<div class=\"mw-editTools\">\n$edittools_text\n</div>"; + } + } + $this->free_text_was_included = true; + $this->wiki_page->addFreeTextSection(); + } + + if ( $this->tif->getTemplateName() === '' || $field_name == '#freetext#' ) { + $this->section = substr_replace( $this->section, $this->new_text, $this->brackets_loc, $this->brackets_end_loc + 3 - $this->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 ( $this->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 ( $this->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 ( $this->tif->allInstancesPrinted() && $form_field->getDefaultValue() == null ) { + $cur_value = null; + } + + $this->new_text = $this->formFieldHTML( $form_field, $cur_value ); + $this->new_text .= $form_field->additionalHTMLForInput( $cur_value, $field_name, $this->tif->getTemplateName() ); + + if ( $this->new_text ) { + $this->wiki_page->addTemplateParam( $this->template_name, $this->tif->getInstanceNum(), $field_name, $cur_value_in_template ); + $this->section = substr_replace( $this->section, $this->new_text, $this->brackets_loc, $this->brackets_end_loc + 3 - $this->brackets_loc ); + } else { + $start_position = $this->brackets_end_loc; + } + } + + if ( $this->tif->allowsMultiple() && !$this->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 ( $this->tif->getDisplay() != null && ( !$this->tif->allowsMultiple() || !$this->tif->allInstancesPrinted() ) ) { + $this->tif->addGridValue( $field_name, $cur_value ); + } + } + + // handles {{{standard input}}} + private function tagStandardInput() { + // handle all the possible values + $input_name = $this->tag_components[1]; + $input_label = null; + $attr = array(); + + // if it's a query, ignore all standard inputs except run query + if ( ( $this->is_query && $input_name != 'run query' ) || ( !$this->is_query && $input_name == 'run query' ) ) { + $this->new_text = ""; + $this->section = substr_replace( $this->section, $this->new_text, $this->brackets_loc, $this->brackets_end_loc + 3 - $this->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( $this->tag_components ); $i++ ) { + $component = $this->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' ); + $this->new_text = PFFormUtils::summaryInputHTML( $this->form_is_disabled, $input_label, $attr, $value ); + } elseif ( $input_name == 'minor edit' ) { + $is_checked = $wgRequest->getCheck( 'wpMinoredit' ); + $this->new_text = PFFormUtils::minorEditInputHTML( $this->form_submitted, $this->form_is_disabled, $is_checked, $input_label, $attr ); + } elseif ( $input_name == 'watch' ) { + $is_checked = $wgRequest->getCheck( 'wpWatchthis' ); + $this->new_text = PFFormUtils::watchInputHTML( $this->form_submitted, $this->form_is_disabled, $is_checked, $input_label, $attr ); + } elseif ( $input_name == 'save' ) { + $this->new_text = PFFormUtils::saveButtonHTML( $this->form_is_disabled, $input_label, $attr ); + } elseif ( $input_name == 'save and continue' ) { + $this->new_text = PFFormUtils::saveAndContinueButtonHTML( $this->form_is_disabled, $input_label, $attr ); + } elseif ( $input_name == 'preview' ) { + $this->new_text = PFFormUtils::showPreviewButtonHTML( $this->form_is_disabled, $input_label, $attr ); + } elseif ( $input_name == 'changes' ) { + $this->new_text = PFFormUtils::showChangesButtonHTML( $this->form_is_disabled, $input_label, $attr ); + } elseif ( $input_name == 'cancel' ) { + $this->new_text = PFFormUtils::cancelLinkHTML( $this->form_is_disabled, $input_label, $attr ); + } elseif ( $input_name == 'run query' ) { + $this->new_text = PFFormUtils::runQueryButtonHTML( $this->form_is_disabled, $input_label, $attr ); + } + $this->section = substr_replace( $this->section, $this->new_text, $this->brackets_loc, $this->brackets_end_loc + 3 - $this->brackets_loc ); + } + + // function to handle the {{{section}}} tag + private function tagSection() { + global $wgRequest; + global $wgPageFormsFieldNum; + global $wgPageFormsTabIndex; + $wgPageFormsFieldNum++; + $wgPageFormsTabIndex++; + + $section_name = trim( $this->tag_components[1] ); + $page_section_in_form = PFPageSection::newFromFormTag( $this->tag_components ); + $section_text = null; + + // Split the existing page contents into the textareas in the form. + $default_value = ""; + $section_start_loc = 0; + if ( $this->source_is_page && $this->existing_page_content !== null ) { + // For the last section of the page, there is no trailing newline in + // $this->existing_page_content, but the code below expects it. This code + // ensures that there is always trailing newline. T72202 + if ( substr( $this->existing_page_content, -1 ) !== "\n" ) { + $this->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, $this->existing_page_content, $matches, PREG_OFFSET_CAPTURE ) ) { + $section_start_loc = $matches[0][1]; + $header_text = $matches[0][0]; + $this->existing_page_content = str_replace( $header_text, '', $this->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( $this->section, '{{{', $this->brackets_end_loc ); + if ( $next_section_start_loc == false ) { + $section_end_loc = strpos( $this->existing_page_content, '{{', $section_start_loc ); + } else { + $next_section_end_loc = strpos( $this->section, '}}}', $next_section_start_loc ); + $bracketed_string_next_section = substr( $this->section, $next_section_start_loc + 3, $next_section_end_loc - ( $next_section_start_loc + 3 ) ); + $this->tag_components_next_section = PFUtils::getFormTagComponents( $bracketed_string_next_section ); + $tag_title_next_section = trim( $this->tag_components_next_section[0] ); + if ( $tag_title_next_section == 'section' ) { + if ( preg_match( '/(^={1,6}[ ]*?' . $this->tag_components_next_section[1] . '[ ]*?={1,6}\s*?$)/m', $this->existing_page_content, $matches, PREG_OFFSET_CAPTURE ) ) { + $section_end_loc = $matches[0][1]; + } + } + } + + if ( $section_end_loc === -1 ) { + $section_text = $this->existing_page_content; + $this->existing_page_content = ''; + } else { + $section_text = substr( $this->existing_page_content, $section_start_loc, $section_end_loc - $section_start_loc ); + $this->existing_page_content = substr( $this->existing_page_content, $section_end_loc ); + } + } + + // If input is from the form. + if ( ( ! $this->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(); + } + + $this->section = substr_replace( $this->section, $form_section_text, $this->brackets_loc, $this->brackets_end_loc + 3 - $this->brackets_loc ); + } + + // handles {{{info}}} + private function tagInfo() { + // TODO: Generate an error message if this is included more than once + foreach ( array_slice( $this->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 ( !$this->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 ( !$this->is_query && $this->mPageTitle->exists() ) { + $form_page_title = $sub_components[1]; + } + } elseif ( $tag == 'query title' ) { + // Handle this only if + // we're in 'RunQuery'. + if ( $this->is_query ) { + $form_page_title = $sub_components[1]; + } + } elseif ( $tag == 'partial form' ) { + $this->form_is_partial = true; + // replacement pages may have minimal matches... + $this->source_page_matches_this_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; + } + } + $this->section = substr_replace( $this->section, '', $this->brackets_loc, $this->brackets_end_loc + 3 - $this->brackets_loc ); + } + /** * This function is the real heart of the entire Page Forms * extension. It handles two main actions: (1) displaying a form on the @@ -826,18 +1316,18 @@ // @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 ) ); + while ( $this->brackets_loc = strpos( $form_def, "{{{", $start_position ) ) { + $this->brackets_end_loc = strpos( $form_def, "}}}", $this->brackets_loc ); + $bracketed_string = substr( $form_def, $this->brackets_loc + 3, $this->brackets_end_loc - ( $this->brackets_loc + 3 ) ); $this->tag_components = PFUtils::getFormTagComponents( $bracketed_string ); $tag_title = trim( $this->tag_components[0] ); if ( $tag_title == 'for template' || $tag_title == 'end template' ) { // Create a section for everything up to here - $this->section = substr( $form_def, $section_start, $brackets_loc - $section_start ); + $this->section = substr( $form_def, $section_start, $this->brackets_loc - $section_start ); $form_def_sections[] = $this->section; - $section_start = $brackets_loc; + $section_start = $this->brackets_loc; } - $start_position = $brackets_loc + 1; + $start_position = $this->brackets_loc + 1; } // end while $form_def_sections[] = trim( substr( $form_def, $section_start ) ); @@ -857,509 +1347,49 @@ // array doesn't get modified; is it necessary? $this->section = " " . $form_def_sections[$section_num]; - while ( $brackets_loc = strpos( $this->section, '{{{', $start_position ) ) { - $brackets_end_loc = strpos( $this->section, "}}}", $brackets_loc ); - $bracketed_string = substr( $this->section, $brackets_loc + 3, $brackets_end_loc - ( $brackets_loc + 3 ) ); + while ( $this->brackets_loc = strpos( $this->section, '{{{', $start_position ) ) { + $this->brackets_end_loc = strpos( $this->section, "}}}", $this->brackets_loc ); + $bracketed_string = substr( $this->section, $this->brackets_loc + 3, $this->brackets_end_loc - ( $this->brackets_loc + 3 ) ); $this->tag_components = PFUtils::getFormTagComponents( $bracketed_string ); $tag_title = trim( $this->tag_components[0] ); // ===================================================== // for template processing // ===================================================== if ( $tag_title == 'for template' ) { - if ( $this->tif ) { - $previous_template_name = $this->tif->getTemplateName(); - } else { - $previous_template_name = ''; - } - $this->template_name = str_replace( '_', ' ', $this->tag_components[1] ); - $is_new_template = ( $this->template_name != $previous_template_name ); - if ( $is_new_template ) { - $this->template = PFTemplate::newFromName( $this->template_name ); - $this->tif = PFTemplateInForm::newFromFormTag( $this->tag_components ); - } - // Remove template tag. - $this->section = substr_replace( $this->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 ( $this->source_is_page || $this->partial_form_submitted ) { - $this->tif->setPageRelatedInfo( $this->existing_page_content ); - // Get the first instance of this template on the page - // being edited, even if there are more. - if ( $this->tif->pageCallsThisTemplate() ) { - $this->tif->setFieldValuesFromPage( $this->existing_page_content ); - $existing_template_text = $this->tif->getFullTextInPage(); - // Now remove this template from the text being edited. - // If this is a partial form, establish a new insertion point. - if ( $this->existing_page_content && $this->partial_form_submitted ) { - // If something already exists, set the new insertion point - // to its position; otherwise just let it lie. - if ( strpos( $this->existing_page_content, $existing_template_text ) !== false ) { - $this->existing_page_content = str_replace( "\n" . '{{{insertionpoint}}}', '', $this->existing_page_content ); - $this->existing_page_content = str_replace( $existing_template_text, '{{{insertionpoint}}}', $this->existing_page_content ); - } - } else { - $this->existing_page_content = $this->strReplaceFirst( $existing_template_text, '', $this->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_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. - $this->tif->setFieldValuesFromSubmit(); - - $this->tif->checkIfAllInstancesPrinted( $this->form_submitted, $this->source_is_page ); - - if ( !$this->tif->allInstancesPrinted() ) { - $this->wiki_page->addTemplate( $this->tif ); - } - + $this->tagForTemplate(); // ===================================================== // end template processing // ===================================================== } elseif ( $tag_title == 'end template' ) { - if ( $this->source_is_page ) { - // Add any unhandled template fields - // in the page as hidden variables. - $this->form_text .= PFFormUtils::unhandledFieldsHTML( $this->tif ); - } - // Remove this tag from the $this->section variable. - $this->section = substr_replace( $this->section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - $this->template = null; - $this->tif = null; + $this->tagEndTemplate(); // ===================================================== // 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 ( $this->tif == null ) { - $this->template = new PFTemplate( null, array() ); - $this->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( $this->tag_components[1] ); - $form_field = PFFormField::newFromFormFieldTag( $this->tag_components, $this->template, $this->tif, $this->form_is_disabled ); - // For special displays, add in the form fields, so we know the data structure. - if ( ( $this->tif->getDisplay() == 'table' && ( !$this->tif->allowsMultiple() || $this->tif->getInstanceNum() == 0 ) ) || - ( $this->tif->getDisplay() == 'spreadsheet' && $this->tif->allowsMultiple() && $this->tif->getInstanceNum() == 0 ) ) { - $this->tif->addField( $form_field ); - } - $cur_value = $form_field->getCurrentValue( $this->tif->getValuesFromSubmit(), $this->form_submitted, $this->source_is_page, $this->tif->allInstancesPrinted() ); - if ( $form_field->holdsTemplate() ) { - $this->placeholderFields[] = self::placeholderFormat( $this->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 ( $this->source_is_page && ( $this->tif->getFullTextInPage() != '' && !$this->form_submitted ) ) { - if ( $this->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 = $this->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() ) { - $this->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() ) { - $this->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(); - $this->new_text = $freeTextInput->getHtmlText(); - if ( $form_field->hasFieldArg( 'edittools' ) ) { - // borrowed from EditPage::showEditTools() - $edittools_text = $wgParser->recursiveTagParse( wfMessage( 'edittools', array( 'content' ) )->text() ); - - $this->new_text .= <<<END - <div class="mw-editTools"> - $edittools_text - </div> - -END; - } - } - $this->free_text_was_included = true; - $this->wiki_page->addFreeTextSection(); - } - - if ( $this->tif->getTemplateName() === '' || $field_name == '#freetext#' ) { - $this->section = substr_replace( $this->section, $this->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 ( $this->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 ( $this->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 ( $this->tif->allInstancesPrinted() && $form_field->getDefaultValue() == null ) { - $cur_value = null; - } - - $this->new_text = $this->formFieldHTML( $form_field, $cur_value ); - $this->new_text .= $form_field->additionalHTMLForInput( $cur_value, $field_name, $this->tif->getTemplateName() ); - - if ( $this->new_text ) { - $this->wiki_page->addTemplateParam( $this->template_name, $this->tif->getInstanceNum(), $field_name, $cur_value_in_template ); - $this->section = substr_replace( $this->section, $this->new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - } else { - $start_position = $brackets_end_loc; - } - } - - if ( $this->tif->allowsMultiple() && !$this->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 ( $this->tif->getDisplay() != null && ( !$this->tif->allowsMultiple() || !$this->tif->allInstancesPrinted() ) ) { - $this->tif->addGridValue( $field_name, $cur_value ); - } - + $this->tagField(); // ===================================================== // standard input processing // ===================================================== } elseif ( $tag_title == 'standard input' ) { - // handle all the possible values - $input_name = $this->tag_components[1]; - $input_label = null; - $attr = array(); - - // if it's a query, ignore all standard inputs except run query - if ( ( $this->is_query && $input_name != 'run query' ) || ( !$this->is_query && $input_name == 'run query' ) ) { - $this->new_text = ""; - $this->section = substr_replace( $this->section, $this->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( $this->tag_components ); $i++ ) { - $component = $this->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' ); - $this->new_text = PFFormUtils::summaryInputHTML( $this->form_is_disabled, $input_label, $attr, $value ); - } elseif ( $input_name == 'minor edit' ) { - $is_checked = $wgRequest->getCheck( 'wpMinoredit' ); - $this->new_text = PFFormUtils::minorEditInputHTML( $this->form_submitted, $this->form_is_disabled, $is_checked, $input_label, $attr ); - } elseif ( $input_name == 'watch' ) { - $is_checked = $wgRequest->getCheck( 'wpWatchthis' ); - $this->new_text = PFFormUtils::watchInputHTML( $this->form_submitted, $this->form_is_disabled, $is_checked, $input_label, $attr ); - } elseif ( $input_name == 'save' ) { - $this->new_text = PFFormUtils::saveButtonHTML( $this->form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'save and continue' ) { - $this->new_text = PFFormUtils::saveAndContinueButtonHTML( $this->form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'preview' ) { - $this->new_text = PFFormUtils::showPreviewButtonHTML( $this->form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'changes' ) { - $this->new_text = PFFormUtils::showChangesButtonHTML( $this->form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'cancel' ) { - $this->new_text = PFFormUtils::cancelLinkHTML( $this->form_is_disabled, $input_label, $attr ); - } elseif ( $input_name == 'run query' ) { - $this->new_text = PFFormUtils::runQueryButtonHTML( $this->form_is_disabled, $input_label, $attr ); - } - $this->section = substr_replace( $this->section, $this->new_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + $this->tagStandardInput(); // ===================================================== // for section processing // ===================================================== } elseif ( $tag_title == 'section' ) { - $wgPageFormsFieldNum++; - $wgPageFormsTabIndex++; - - $section_name = trim( $this->tag_components[1] ); - $page_section_in_form = PFPageSection::newFromFormTag( $this->tag_components ); - $section_text = null; - - // Split the existing page contents into the textareas in the form. - $default_value = ""; - $section_start_loc = 0; - if ( $this->source_is_page && $this->existing_page_content !== null ) { - // For the last section of the page, there is no trailing newline in - // $this->existing_page_content, but the code below expects it. This code - // ensures that there is always trailing newline. T72202 - if ( substr( $this->existing_page_content, -1 ) !== "\n" ) { - $this->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, $this->existing_page_content, $matches, PREG_OFFSET_CAPTURE ) ) { - $section_start_loc = $matches[0][1]; - $header_text = $matches[0][0]; - $this->existing_page_content = str_replace( $header_text, '', $this->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( $this->section, '{{{', $brackets_end_loc ); - if ( $next_section_start_loc == false ) { - $section_end_loc = strpos( $this->existing_page_content, '{{', $section_start_loc ); - } else { - $next_section_end_loc = strpos( $this->section, '}}}', $next_section_start_loc ); - $bracketed_string_next_section = substr( $this->section, $next_section_start_loc + 3, $next_section_end_loc - ( $next_section_start_loc + 3 ) ); - $this->tag_components_next_section = PFUtils::getFormTagComponents( $bracketed_string_next_section ); - $tag_title_next_section = trim( $this->tag_components_next_section[0] ); - if ( $tag_title_next_section == 'section' ) { - if ( preg_match( '/(^={1,6}[ ]*?' . $this->tag_components_next_section[1] . '[ ]*?={1,6}\s*?$)/m', $this->existing_page_content, $matches, PREG_OFFSET_CAPTURE ) ) { - $section_end_loc = $matches[0][1]; - } - } - } - - if ( $section_end_loc === -1 ) { - $section_text = $this->existing_page_content; - $this->existing_page_content = ''; - } else { - $section_text = substr( $this->existing_page_content, $section_start_loc, $section_end_loc - $section_start_loc ); - $this->existing_page_content = substr( $this->existing_page_content, $section_end_loc ); - } - } - - // If input is from the form. - if ( ( ! $this->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(); - } - - $this->section = substr_replace( $this->section, $form_section_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + $this->tagSection(); // ===================================================== // page info processing // ===================================================== } elseif ( $tag_title == 'info' ) { - // TODO: Generate an error message if this is included more than once - foreach ( array_slice( $this->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 ( !$this->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 ( !$this->is_query && $this->mPageTitle->exists() ) { - $form_page_title = $sub_components[1]; - } - } elseif ( $tag == 'query title' ) { - // Handle this only if - // we're in 'RunQuery'. - if ( $this->is_query ) { - $form_page_title = $sub_components[1]; - } - } elseif ( $tag == 'partial form' ) { - $this->form_is_partial = true; - // replacement pages may have minimal matches... - $this->source_page_matches_this_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; - } - } - $this->section = substr_replace( $this->section, '', $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); + $this->tagInfo(); // ===================================================== // 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( $this->section, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ) ); - $this->section = substr_replace( $this->section, $form_section_text, $brackets_loc, $brackets_end_loc + 3 - $brackets_loc ); - $start_position = $brackets_end_loc; + $form_section_text = htmlspecialchars( substr( $this->section, $this->brackets_loc, $this->brackets_end_loc + 3 - $this->brackets_loc ) ); + $this->section = substr_replace( $this->section, $form_section_text, $this->brackets_loc, $this->brackets_end_loc + 3 - $this->brackets_loc ); + $start_position = $this->brackets_end_loc; } // end if } // end while -- To view, visit https://gerrit.wikimedia.org/r/360339 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I3ec87e0ca1622fd4dc0eb3b57cc45dba8711abfa 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