summaryrefslogtreecommitdiff
blob: 13b2db8040715febc22c9749d653631c0d40f7ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
<?php
/**
 * File holding the SFFormInput class.
 *
 * The predecessor of this file held several subclasses of SFFormInput. The
 * authors can not be sorted out with certainty anymore, thus are all listed
 * here.
 *
 * @author Yaron Koren
 * @author Jeffrey Stuckman
 * @author Matt Williamson
 * @author Patrick Nagel
 * @author Sanyam Goyal
 * @author Stephan Gambke
 * @file
 * @ingroup SF
 */

/**
 * Parent class for all form input classes.
 * @ingroup SFFormInput
 */
abstract class SFFormInput {

	protected $mInputNumber;
	protected $mCurrentValue;
	protected $mInputName;
	protected $mIsMandatory; // @deprecated, check for array_key_exists('mandatory', $this->mOtherArgs) instead
	protected $mIsDisabled;
	protected $mOtherArgs;

	protected $mJsInitFunctionData = array();
	protected $mJsValidationFunctionData = array();

	/**
	 * Constructor for the SFFormInput class.
	 *
	 * @param String $input_number
	 *		The number of the input in the form. For a simple HTML input element
	 *      this should end up in the id attribute in the format 'input_<number>'.
	 * @param String $cur_value
	 *		The current value of the input field. For a simple HTML input
	 *		element this should end up in the value attribute.
	 * @param String $input_name
	 *		The name of the input. For a simple HTML input element this should
	 *		end up in the name attribute.
	 * @param Array $other_args
	 *		An associative array of other parameters that were present in the
	 *		input definition.
	 */
	public function __construct( $input_number, $cur_value, $input_name, $disabled, $other_args ) {
		$this->mInputNumber = $input_number;
		$this->mCurrentValue = $cur_value;
		$this->mInputName = $input_name;
		$this->mOtherArgs = $other_args;
		$this->mIsDisabled = $disabled;
		$this->mIsMandatory = array_key_exists( 'mandatory', $other_args );
	}

	/**
	 * Returns the name of the input type this class handles.
	 *
	 * This is the name to be used in the field definition for the "input type"
	 * parameter.
	 *
	 * @return String The name of the input type this class handles.
	 * @fixme Should be declared abstract. Static functions cannot be abstract.
	 * Do we need this method at all? The name should be set outside this class
	 * when the input type is registered.
	 */
	public static function getName() {
		return null;
	}

	/**
	 * Returns the set of SMW property types which this input can
	 * handle. See SMW's SMW_DataValueFactory.php
	 *
	 * @return Array of Strings
	 */
	public static function getHandledPropertyTypes() {
		return null;
	}

	/**
	 * Returns the set of parameters for this form input.
	 */
	public static function getParameters() {
		$params = array();
		$params['mandatory'] = array(
			'name' => 'mandatory',
			'type' => 'boolean',
			'description' => wfMessage( 'sf_forminputs_mandatory' )->text()
		);
		$params['restricted'] = array(
			'name' => 'restricted',
			'type' => 'boolean',
			'description' => wfMessage( 'sf_forminputs_restricted' )->text()
		);
		$params['class'] = array(
			'name' => 'class',
			'type' => 'string',
			'description' => wfMessage( 'sf_forminputs_class' )->text()
		);
		$params['property'] = array(
			'name' => 'property',
			'type' => 'string',
			'description' => wfMessage( 'sf_forminputs_property' )->text()
		);
		$params['default'] = array(
			'name' => 'default',
			'type' => 'string',
			'description' => wfMessage( 'sf_forminputs_default' )->text()
		);
		return $params;
	}

	/**
	 * Return an array of the default parameters for this input where the
	 * parameter name is the key while the parameter value is the value.
	 *
	 * @return Array of Strings
	 */
	public function getDefaultParameters() {
		return null;
	}

	/**
	 * Returns the HTML code to be included in the output page for this input.
	 *
	 * Ideally this HTML code should provide a basic functionality even if the
	 * browser is not JavaScript capable. I.e. even without JavaScript the user
	 * should be able to input values.
	 *
	 * This function is not used yet.
	 */
	public function getHtmlText() {
		return null;
	}

	/**
	 *
	 * @return Boolean True, if this input type can handle lists
	 */
	public static function canHandleLists() {
		return false;
	}

	/**
	 * Returns the name and parameters for the initialization JavaScript
	 * function for this input type, if any.
	 *
	 * This function is not used yet.
	 */
	public function getJsInitFunctionData() {
		return $this->mJsInitFunctionData;
	}

	/**
	 * Returns the name and parameters for the validation JavaScript
	 * functions for this input type, if any.
	 *
	 * This function is not used yet.
	 */
	public function getJsValidationFunctionData() {
		return $this->mJsValidationFunctionData;
	}


	/**
	 * Returns the names of the resource modules this input type uses.
	 *
	 * Returns the names of the modules as an array or - if there is only one
	 * module - as a string.
	 *
	 * @return null|string|array
	 */
	public function getResourceModuleNames() {
		return null;
	}

	/**
	 * For each input type one or more JavaScript initialization functions may
	 * be specified.
	 *
	 * <b>This function is not used yet.</b>
	 *
	 * They are called to initialize the input after the page html has loaded
	 * (or for "multiple" templates after the page fragment has loaded).
	 *
	 * The JavaScript function specified here must be in the top level scope of
	 * the document. When it is called it will get the input's id attribute as
	 * the first parameter and the specified param as the second.
	 *
	 *
	 * Examples:
	 *
	 * Adding initFoo like this: <code>addJsInitFunctionData( "initFoo", "'bar'" );</code> will result in this JavaScript call: <code>initFoo( inputID, 'bar' );</code>.
	 *
	 * Adding initFoo like this: <code>addJsInitFunctionData( "initFoo", "array('bar', 'baz'" );</code> will result in this JavaScript call: <code>initFoo( inputID, array('bar', 'baz') );</code>.
	 *
	 *
	 * @param String $name The name of the initialization function.
	 * @param String $param The parameter passed to the initialization function.
	 */
	public function addJsInitFunctionData( $name, $param = 'null' ) {
		$this->mJsInitFunctionData[] = array( 'name' => $name, 'param' => $param );
	}

	/**
	 * For each input type one or more JavaScript validation functions may
	 * be specified.
	 *
	 * <b>Not used yet.</b>
	 *
	 * They are called to validate the input before the form is submitted for
	 * saving or preview.
	 *
	 * The JavaScript function specified here must be in the top level scope of
	 * the document. When it is called it will get the input's id attribute as
	 * the first parameter and the specified param as the second.
	 *
	 *
	 * Examples:
	 *
	 * Adding validateFoo like this: <code>addJsValidationFunctionData( "initFoo", "'bar'" );</code> will result in this JavaScript call: <code>validateFoo( inputID, 'bar' );</code>.
	 *
	 * Adding validateFoo like this: <code>addJsValidationFunctionData( "initFoo", "array('bar', 'baz'" );</code> will result in this JavaScript call: <code>validateFoo( inputID, array('bar', 'baz') );</code>.
	 *
	 *
	 * @param String $name The name of the initialization function.
	 * @param String $param The parameter passed to the initialization function.
	 */
	public function addJsValidationFunctionData( $name, $param = 'null' ) {
		$this->mJsValidationFunctionData[] = array( 'name' => $name, 'param' => $param );
	}

	/**
	 * Returns the set of SMW property types for which this input is
	 * meant to be the default one - ideally, no more than one input
	 * should declare itself the default for any specific type.
	 *
	 * @deprecated
	 * @return Array of arrays (key is the property type, value is an array of
	 *  default args to be used for this input)
	 */
	public static function getDefaultPropTypes() {
		return array();
	}

	/**
	 * Returns the set of SMW property types for which this input is
	 * meant to be the default one - ideally, no more than one input
	 * should declare itself the default for any specific type.
	 *
	 * @deprecated
	 * @return Array of arrays (key is the property type, value is an array of
	 *  default args to be used for this input)
	 */
	public static function getDefaultPropTypeLists() {
		return array();
	}

	/**
	 * Returns the set of SMW property types which this input can
	 * handle, but for which it isn't the default input.
	 *
	 * @deprecated
	 * @return Array of strings
	 */
	public static function getOtherPropTypesHandled() {
		return array();
	}

	/**
	 * Returns the set of SMW property types which this input can
	 * handle, but for which it isn't the default input.
	 *
	 * @deprecated
	 * @return Array of strings
	 */
	public static function getOtherPropTypeListsHandled() {
		return array();
	}

	/**
	 * Method to make new style input types compatible with old-style call from
	 * the SF parser.
	 *
	 * @deprecated Do not use/override this in new input type classes
	 *
	 * TODO: remove/refactor once SF uses forminput objects properly
	 */
	public static function getHTML( $cur_value, $input_name, $is_mandatory, $is_disabled, $other_args ) {

		global $sfgFieldNum, $wgParser;

		// create an input of the called class
		// TODO: get_called_class was introduced in PHP 5.3. The use of the
		// backtrace should be removed once support for PHP 5.2 is dropped.
		if ( function_exists('get_called_class') ) {
			$calledClass = get_called_class();
		} else {
			if ( $input_name === 'sf_free_text' ) { // free text
				$calledClass = 'SFTextAreaInput';
			} else {
				$bt = debug_backtrace(false);
				$calledClass = $bt[1]['args'][0][0];
			}
		}

		$input = new $calledClass ( $sfgFieldNum, $cur_value, $input_name, $is_disabled, $other_args );

		$output = $wgParser->getOutput();
		$modules = $input->getResourceModuleNames();

		// register modules for the input
		if ( $modules !== null ) {
			$output->addModuleStyles( $modules );
			$output->addModuleScripts( $modules );
		}

		// create calls to JS initialization and validation
		// TODO: This data should be transferred as a JSON blob and then be evaluated from a dedicated JS file
		if ( $input->getJsInitFunctionData() || $input->getJsValidationFunctionData() ) {

			$jstext = '';
			$input_id = $input_name == 'sf_free_text' ? 'sf_free_text' : "input_$sfgFieldNum";

			foreach ( $input->getJsInitFunctionData() as $jsInitFunctionData ) {
				$jstext .= "jQuery('#$input_id').SemanticForms_registerInputInit({$jsInitFunctionData['name']}, {$jsInitFunctionData['param']} );";
			}

			foreach ( $input->getJsValidationFunctionData() as $jsValidationFunctionData ) {
				$jstext .= "jQuery('#$input_id').SemanticForms_registerInputValidation( {$jsValidationFunctionData['name']}, {$jsValidationFunctionData['param']});";
			}

			if ( $modules !== null ) {
				$jstext = 'mw.loader.using(' . json_encode( $modules )
					. ',function(){' . $jstext
					. '},function(e,module){alert(module+": "+e);});';
			}

			$jstext = 'jQuery(function(){' . $jstext . '});';

			// write JS code directly to the page's code
			$output->addHeadItem( Html::inlineScript( $jstext ) );
		}

		return $input->getHtmlText();
	}

}