Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 118 |
|
0.00% |
0 / 1 |
CRAP | |
0.00% |
0 / 1 |
PFFormInputParserFunction | |
0.00% |
0 / 118 |
|
0.00% |
0 / 1 |
1190 | |
0.00% |
0 / 1 |
run | |
0.00% |
0 / 118 |
|
0.00% |
0 / 1 |
1190 |
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\MediaWikiServices; |
37 | |
38 | class PFFormInputParserFunction { |
39 | /** |
40 | * static variable to guarantee that JavaScript for autocompletion |
41 | * only gets added to the page once. |
42 | */ |
43 | private static $num_autocompletion_inputs = 0; |
44 | |
45 | public static function run( Parser $parser ) { |
46 | global $wgCapitalLinks; |
47 | |
48 | $params = func_get_args(); |
49 | // We don't need the parser. |
50 | array_shift( $params ); |
51 | |
52 | $parser->getOutput()->addModules( [ 'ext.pageforms.forminput' ] ); |
53 | |
54 | // Set defaults. |
55 | $inFormName = $inValue = $inButtonStr = ''; |
56 | $inQueryArr = []; |
57 | $inAutocompletionSource = ''; |
58 | $inSize = ''; |
59 | $classStr = "pfFormInput"; |
60 | $inNamespaceSelector = null; |
61 | $inPlaceholder = null; |
62 | $inAutofocus = true; |
63 | $hasPopup = $hasReturnTo = false; |
64 | |
65 | // Assign params. |
66 | foreach ( $params as $i => $param ) { |
67 | $elements = explode( '=', $param, 2 ); |
68 | |
69 | // Set param name and value. |
70 | if ( count( $elements ) > 1 ) { |
71 | $paramName = trim( $elements[0] ); |
72 | // Parse (and sanitize) parameter values. |
73 | // We call recursivePreprocess() and not |
74 | // recursiveTagParse() so that URL values will |
75 | // not be turned into links. |
76 | $value = trim( $parser->recursivePreprocess( html_entity_decode( $elements[1], ENT_QUOTES ) ) ); |
77 | } else { |
78 | $paramName = trim( $param ); |
79 | $value = null; |
80 | } |
81 | |
82 | if ( $paramName == 'form' ) { |
83 | $inFormName = $value; |
84 | } elseif ( $paramName == 'size' ) { |
85 | $inSize = $value; |
86 | } elseif ( $paramName == 'default value' ) { |
87 | $inValue = $value; |
88 | } elseif ( $paramName == 'button text' ) { |
89 | $inButtonStr = $value; |
90 | } elseif ( $paramName == 'query string' ) { |
91 | $inQueryArr = PFAutoEdit::convertQueryString( $value, $inQueryArr ); |
92 | } elseif ( $paramName == 'autocomplete on category' ) { |
93 | $inAutocompletionSource = $value; |
94 | $autocompletionType = 'category'; |
95 | } elseif ( $paramName == 'autocomplete on namespace' ) { |
96 | $inAutocompletionSource = $value; |
97 | $autocompletionType = 'namespace'; |
98 | } elseif ( $paramName == 'namespace selector' ) { |
99 | $inNamespaceSelector = explode( ',', $value ); |
100 | } elseif ( $paramName == 'placeholder' ) { |
101 | $inPlaceholder = $value; |
102 | } elseif ( $paramName == 'popup' ) { |
103 | PFFormLink::loadScriptsForPopupForm( $parser ); |
104 | $classStr .= ' popupforminput'; |
105 | $hasPopup = true; |
106 | } elseif ( $paramName == 'reload' ) { |
107 | $classStr .= ' reload'; |
108 | $inQueryArr['reload'] = '1'; |
109 | } elseif ( $paramName == 'no autofocus' ) { |
110 | $inAutofocus = false; |
111 | } else { |
112 | $value = urlencode( $value ); |
113 | parse_str( "$paramName=$value", $arr ); |
114 | $inQueryArr = PFUtils::arrayMergeRecursiveDistinct( $inQueryArr, $arr ); |
115 | if ( $paramName == 'returnto' ) { |
116 | $hasReturnTo = true; |
117 | } |
118 | } |
119 | } |
120 | |
121 | if ( $hasPopup && $hasReturnTo ) { |
122 | return '<div class="error">Error: \'popup\' and \'returnto\' cannot be set in the same function.</div>'; |
123 | } |
124 | |
125 | $formInputAttrs = [ |
126 | 'class' => 'pfFormInputWrapper', |
127 | 'data-size' => $inSize |
128 | ]; |
129 | |
130 | $formContents = ''; |
131 | |
132 | if ( $inValue != null ) { |
133 | $formInputAttrs['data-default-value'] = $inValue; |
134 | } |
135 | |
136 | if ( $inNamespaceSelector !== null ) { |
137 | foreach ( $inNamespaceSelector as &$nsName ) { |
138 | $nsName = htmlspecialchars( trim( $nsName ) ); |
139 | } |
140 | $possibleNamespacesStr = implode( '|', $inNamespaceSelector ); |
141 | $formInputAttrs['data-possible-namespaces'] = $possibleNamespacesStr; |
142 | } |
143 | |
144 | if ( $inPlaceholder != null ) { |
145 | $formInputAttrs['data-placeholder'] = $inPlaceholder; |
146 | } |
147 | if ( $inAutofocus ) { |
148 | $formInputAttrs['data-autofocus'] = true; |
149 | } |
150 | if ( !$wgCapitalLinks ) { |
151 | $formInputAttrs['data-autocapitalize'] = 'off'; |
152 | } |
153 | |
154 | // Now apply the necessary settings and JavaScript, depending |
155 | // on whether or not there's autocompletion (and whether the |
156 | // autocompletion is local or remote). |
157 | $input_num = 1; |
158 | if ( !empty( $inAutocompletionSource ) ) { |
159 | self::$num_autocompletion_inputs++; |
160 | $input_num = self::$num_autocompletion_inputs; |
161 | $inputID = 'input_' . $input_num; |
162 | $formInputAttrs['id'] = $inputID; |
163 | // This code formerly only used remote autocompletion |
164 | // when the number of autocompletion values was above |
165 | // a certain limit - as happens in regular forms - |
166 | // but local autocompletion didn't always work, |
167 | // apparently due to page caching. |
168 | $formInputAttrs['data-autocomplete-settings'] = $inAutocompletionSource; |
169 | $formInputAttrs['data-autocomplete-data-type'] = $autocompletionType; |
170 | } |
171 | |
172 | // If the form start URL looks like "index.php?title=Special:FormStart" |
173 | // (i.e., it's in the default URL style), add in the title as a |
174 | // hidden value |
175 | $fs = PFUtils::getSpecialPage( 'FormStart' ); |
176 | $fsURL = $fs->getPageTitle()->getLocalURL(); |
177 | $pos = strpos( $fsURL, "title=" ); |
178 | if ( $pos > -1 ) { |
179 | $formContents .= Html::hidden( "title", urldecode( substr( $fsURL, $pos + 6 ) ) ); |
180 | } |
181 | $listOfForms = preg_split( '~(?<!\\\)' . preg_quote( ',', '~' ) . '~', $inFormName ); |
182 | foreach ( $listOfForms as & $formName ) { |
183 | $formName = str_replace( "\,", ",", $formName ); |
184 | } |
185 | unset( $formName ); |
186 | if ( $inFormName == '' ) { |
187 | try { |
188 | $allForms = PFUtils::getAllForms(); |
189 | } catch ( MWException $e ) { |
190 | return Html::element( 'div', [ 'class' => 'error' ], $e->getMessage() ); |
191 | } |
192 | $formInputAttrs['data-possible-forms'] = implode( '|', $allForms ); |
193 | $formInputAttrs['data-form-label'] = wfMessage( 'pf-formstart-formlabel' )->escaped(); |
194 | } elseif ( count( $listOfForms ) == 1 ) { |
195 | $inFormName = str_replace( '\,', ',', $inFormName ); |
196 | $formContents .= Html::hidden( "form", $inFormName ); |
197 | } else { |
198 | $formInputAttrs['data-possible-forms'] = implode( '|', $listOfForms ); |
199 | $formInputAttrs['data-form-label'] = wfMessage( 'pf-formstart-formlabel' )->escaped(); |
200 | } |
201 | |
202 | // Recreate the passed-in query string as a set of hidden |
203 | // variables. |
204 | if ( !empty( $inQueryArr ) ) { |
205 | // Query string has to be turned into hidden inputs. |
206 | $query_components = explode( '&', http_build_query( $inQueryArr, '', '&' ) ); |
207 | |
208 | foreach ( $query_components as $query_component ) { |
209 | $var_and_val = explode( '=', $query_component, 2 ); |
210 | if ( count( $var_and_val ) == 2 ) { |
211 | $formContents .= Html::hidden( urldecode( $var_and_val[0] ), urldecode( $var_and_val[1] ) ); |
212 | } |
213 | } |
214 | } |
215 | |
216 | $formInputAttrs['data-button-label'] = ( $inButtonStr != '' ) ? $inButtonStr : wfMessage( 'pf_formstart_createoredit' )->escaped(); |
217 | $formContents .= Html::element( 'div', $formInputAttrs, null ); |
218 | |
219 | MediaWikiServices::getInstance()->getHookContainer()->run( 'PageForms::FormInputEnd', [ $params, &$formContents ] ); |
220 | |
221 | $str = "\t" . Html::rawElement( 'form', [ |
222 | 'name' => 'createbox', |
223 | 'action' => $fsURL, |
224 | 'method' => 'get', |
225 | 'class' => $classStr |
226 | ], '<p>' . $formContents . '</p>' |
227 | ) . "\n"; |
228 | |
229 | return [ $str, 'noparse' => true, 'isHTML' => true ]; |
230 | } |
231 | } |