Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 131 |
|
0.00% |
0 / 1 |
CRAP | |
0.00% |
0 / 1 |
| PFFormInputParserFunction | |
0.00% |
0 / 131 |
|
0.00% |
0 / 1 |
1332 | |
0.00% |
0 / 1 |
| run | |
0.00% |
0 / 131 |
|
0.00% |
0 / 1 |
1332 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * '#forminput' is called as: |
| 4 | * |
| 5 | * {{#forminput:form=|size=|default value=|button text=|query string= |
| 6 | * |autocomplete on category=|autocomplete on namespace= |
| 7 | * |popup|reload|...additional query string values...}} |
| 8 | * |
| 9 | * This function returns HTML representing a form to let the user enter the |
| 10 | * name of a page to be added or edited using a Page Forms form. All |
| 11 | * arguments are optional. 'form' is the name of the PF form to be used; |
| 12 | * if it is left empty, a dropdown will appear, letting the user chose among |
| 13 | * all existing forms. 'size' represents the size of the text input (the |
| 14 | * default is the one set by OOUI), and 'default value' is the starting |
| 15 | * value of the input. 'button text' is the text that will appear on the |
| 16 | * "submit" button, and 'query string' is the set of values that you want |
| 17 | * passed in through the query string to the form. (Query string values can |
| 18 | * also be passed in directly as parameters.) |
| 19 | * Finally, you can can specify that the user will get autocompletion using |
| 20 | * the values from a category or namespace of your choice, using |
| 21 | * 'autocomplete on category' or 'autocomplete on namespace' (you can only |
| 22 | * use one). To autocomplete on all pages in the main (blank) |
| 23 | * namespace, specify "autocomplete on namespace=main". |
| 24 | * 'reload' is an optional parameter that can be used alongside either |
| 25 | * 'popup' or 'returnto'; it causes the page that the user ends up on after |
| 26 | * submitting the form to get reloaded with 'action=purge'. |
| 27 | * |
| 28 | * Example: to create an input to add or edit a page with a form called |
| 29 | * 'User' within a namespace also called 'User', and to have the form |
| 30 | * preload with the page called 'UserStub', you could call the following: |
| 31 | * |
| 32 | * {{#forminput:form=User|button text=Add or edit user |
| 33 | * |query string=namespace=User&preload=UserStub}} |
| 34 | */ |
| 35 | |
| 36 | use MediaWiki\Html\Html; |
| 37 | use MediaWiki\MediaWikiServices; |
| 38 | |
| 39 | class PFFormInputParserFunction { |
| 40 | /** |
| 41 | * static variable to guarantee that JavaScript for autocompletion |
| 42 | * only gets added to the page once. |
| 43 | */ |
| 44 | private static $num_autocompletion_inputs = 0; |
| 45 | |
| 46 | public static function run( Parser $parser ) { |
| 47 | global $wgCapitalLinks; |
| 48 | |
| 49 | $params = func_get_args(); |
| 50 | // We don't need the parser. |
| 51 | array_shift( $params ); |
| 52 | |
| 53 | $parser->getOutput()->addModules( [ 'ext.pageforms.forminput' ] ); |
| 54 | |
| 55 | // Set defaults. |
| 56 | $inFormName = $inValue = $inButtonStr = ''; |
| 57 | $inQueryArr = []; |
| 58 | $inAutocompletionSource = ''; |
| 59 | $inSize = ''; |
| 60 | $classStr = "pfFormInput"; |
| 61 | $inNamespaceSelector = null; |
| 62 | $inPlaceholder = null; |
| 63 | $inAutofocus = true; |
| 64 | $hasPopup = $hasReturnTo = false; |
| 65 | |
| 66 | // Assign params. |
| 67 | foreach ( $params as $i => $param ) { |
| 68 | $elements = explode( '=', $param, 2 ); |
| 69 | |
| 70 | // Set param name and value. |
| 71 | if ( count( $elements ) > 1 ) { |
| 72 | $paramName = trim( $elements[0] ); |
| 73 | // Parse (and sanitize) parameter values. |
| 74 | // We call recursivePreprocess() and not |
| 75 | // recursiveTagParse() so that URL values will |
| 76 | // not be turned into links. |
| 77 | $value = trim( $parser->recursivePreprocess( html_entity_decode( $elements[1], ENT_QUOTES ) ) ); |
| 78 | } else { |
| 79 | $paramName = trim( $param ); |
| 80 | $value = null; |
| 81 | } |
| 82 | |
| 83 | switch ( $paramName ) { |
| 84 | case 'form': |
| 85 | $inFormName = $value; |
| 86 | break; |
| 87 | case 'size': |
| 88 | $inSize = $value; |
| 89 | break; |
| 90 | case 'default value': |
| 91 | $inValue = $value; |
| 92 | break; |
| 93 | case 'button text': |
| 94 | $inButtonStr = $value; |
| 95 | break; |
| 96 | case 'query string': |
| 97 | $inQueryArr = PFAutoEdit::convertQueryString( $value, $inQueryArr ); |
| 98 | break; |
| 99 | case 'autocomplete on category': |
| 100 | $inAutocompletionSource = $value; |
| 101 | $autocompletionType = 'category'; |
| 102 | break; |
| 103 | case 'autocomplete on namespace': |
| 104 | $inAutocompletionSource = $value; |
| 105 | $autocompletionType = 'namespace'; |
| 106 | break; |
| 107 | case 'namespace selector': |
| 108 | $inNamespaceSelector = explode( ',', $value ); |
| 109 | break; |
| 110 | case 'placeholder': |
| 111 | $inPlaceholder = $value; |
| 112 | break; |
| 113 | case 'popup': |
| 114 | PFFormLink::loadScriptsForPopupForm( $parser ); |
| 115 | $classStr .= ' popupforminput'; |
| 116 | $hasPopup = true; |
| 117 | break; |
| 118 | case 'reload': |
| 119 | $classStr .= ' reload'; |
| 120 | $inQueryArr['reload'] = '1'; |
| 121 | break; |
| 122 | case 'no autofocus': |
| 123 | $inAutofocus = false; |
| 124 | break; |
| 125 | default: |
| 126 | if ( $value !== null ) { |
| 127 | $value = urlencode( $value ); |
| 128 | parse_str( "$paramName=$value", $arr ); |
| 129 | $inQueryArr = PFUtils::arrayMergeRecursiveDistinct( $inQueryArr, $arr ); |
| 130 | if ( $paramName === 'returnto' ) { |
| 131 | $hasReturnTo = true; |
| 132 | } |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | if ( $hasPopup && $hasReturnTo ) { |
| 138 | return '<div class="error">Error: \'popup\' and \'returnto\' cannot be set in the same function.</div>'; |
| 139 | } |
| 140 | |
| 141 | $formInputAttrs = [ |
| 142 | 'class' => 'pfFormInputWrapper', |
| 143 | 'data-size' => $inSize |
| 144 | ]; |
| 145 | |
| 146 | $formContents = ''; |
| 147 | |
| 148 | if ( $inValue != null ) { |
| 149 | $formInputAttrs['data-default-value'] = $inValue; |
| 150 | } |
| 151 | |
| 152 | if ( $inNamespaceSelector !== null ) { |
| 153 | foreach ( $inNamespaceSelector as &$nsName ) { |
| 154 | $nsName = htmlspecialchars( trim( $nsName ) ); |
| 155 | } |
| 156 | $possibleNamespacesStr = implode( '|', $inNamespaceSelector ); |
| 157 | $formInputAttrs['data-possible-namespaces'] = $possibleNamespacesStr; |
| 158 | } |
| 159 | |
| 160 | if ( $inPlaceholder != null ) { |
| 161 | $formInputAttrs['data-placeholder'] = $inPlaceholder; |
| 162 | } |
| 163 | if ( $inAutofocus ) { |
| 164 | $formInputAttrs['data-autofocus'] = true; |
| 165 | } |
| 166 | if ( !$wgCapitalLinks ) { |
| 167 | $formInputAttrs['data-autocapitalize'] = 'off'; |
| 168 | } |
| 169 | |
| 170 | // Now apply the necessary settings and JavaScript, depending |
| 171 | // on whether or not there's autocompletion (and whether the |
| 172 | // autocompletion is local or remote). |
| 173 | $input_num = 1; |
| 174 | if ( !empty( $inAutocompletionSource ) ) { |
| 175 | self::$num_autocompletion_inputs++; |
| 176 | $input_num = self::$num_autocompletion_inputs; |
| 177 | $inputID = 'input_' . $input_num; |
| 178 | $formInputAttrs['id'] = $inputID; |
| 179 | // This code formerly only used remote autocompletion |
| 180 | // when the number of autocompletion values was above |
| 181 | // a certain limit - as happens in regular forms - |
| 182 | // but local autocompletion didn't always work, |
| 183 | // apparently due to page caching. |
| 184 | $formInputAttrs['data-autocomplete-settings'] = $inAutocompletionSource; |
| 185 | $formInputAttrs['data-autocomplete-data-type'] = $autocompletionType; |
| 186 | } |
| 187 | |
| 188 | // If the form start URL looks like "index.php?title=Special:FormStart" |
| 189 | // (i.e., it's in the default URL style), add in the title as a |
| 190 | // hidden value |
| 191 | $fs = PFUtils::getSpecialPage( 'FormStart' ); |
| 192 | $fsURL = $fs->getPageTitle()->getLocalURL(); |
| 193 | $pos = strpos( $fsURL, "title=" ); |
| 194 | if ( $pos > -1 ) { |
| 195 | $formContents .= Html::hidden( "title", urldecode( substr( $fsURL, $pos + 6 ) ) ); |
| 196 | } |
| 197 | $listOfForms = preg_split( '~(?<!\\\)' . preg_quote( ',', '~' ) . '~', $inFormName ); |
| 198 | foreach ( $listOfForms as & $formName ) { |
| 199 | $formName = str_replace( "\,", ",", $formName ); |
| 200 | } |
| 201 | unset( $formName ); |
| 202 | if ( $inFormName == '' ) { |
| 203 | try { |
| 204 | $allForms = PFUtils::getAllForms(); |
| 205 | } catch ( MWException $e ) { |
| 206 | return Html::element( 'div', [ 'class' => 'error' ], $e->getMessage() ); |
| 207 | } |
| 208 | $formInputAttrs['data-possible-forms'] = implode( '|', $allForms ); |
| 209 | $formInputAttrs['data-form-label'] = wfMessage( 'pf-formstart-formlabel' )->escaped(); |
| 210 | } elseif ( count( $listOfForms ) == 1 ) { |
| 211 | $inFormName = str_replace( '\,', ',', $inFormName ); |
| 212 | $formContents .= Html::hidden( "form", $inFormName ); |
| 213 | } else { |
| 214 | $formInputAttrs['data-possible-forms'] = implode( '|', $listOfForms ); |
| 215 | $formInputAttrs['data-form-label'] = wfMessage( 'pf-formstart-formlabel' )->escaped(); |
| 216 | } |
| 217 | |
| 218 | // Recreate the passed-in query string as a set of hidden |
| 219 | // variables. |
| 220 | if ( !empty( $inQueryArr ) ) { |
| 221 | // Query string has to be turned into hidden inputs. |
| 222 | $query_components = explode( '&', http_build_query( $inQueryArr, '', '&' ) ); |
| 223 | |
| 224 | foreach ( $query_components as $query_component ) { |
| 225 | $var_and_val = explode( '=', $query_component, 2 ); |
| 226 | if ( count( $var_and_val ) == 2 ) { |
| 227 | $formContents .= Html::hidden( urldecode( $var_and_val[0] ), urldecode( $var_and_val[1] ) ); |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | $formInputAttrs['data-button-label'] = ( $inButtonStr != '' ) ? $inButtonStr : wfMessage( 'pf_formstart_createoredit' )->escaped(); |
| 233 | $formContents .= Html::element( 'div', $formInputAttrs, null ); |
| 234 | |
| 235 | MediaWikiServices::getInstance()->getHookContainer()->run( 'PageForms::FormInputEnd', [ $params, &$formContents ] ); |
| 236 | |
| 237 | $str = "\t" . Html::rawElement( 'form', [ |
| 238 | 'name' => 'createbox', |
| 239 | 'action' => $fsURL, |
| 240 | 'method' => 'get', |
| 241 | 'class' => $classStr |
| 242 | ], '<p>' . $formContents . '</p>' |
| 243 | ) . "\n"; |
| 244 | |
| 245 | return [ $str, 'noparse' => true, 'isHTML' => true ]; |
| 246 | } |
| 247 | } |