Issues (1065)

Themes/default/Post.template.php (4 issues)

1
<?php
2
/**
3
 * Simple Machines Forum (SMF)
4
 *
5
 * @package SMF
6
 * @author Simple Machines https://www.simplemachines.org
7
 * @copyright 2025 Simple Machines and individual contributors
8
 * @license https://www.simplemachines.org/about/smf/license.php BSD
9
 *
10
 * @version 2.1.5
11
 */
12
13
/**
14
 * The main template for the post page.
15
 */
16
function template_main()
17
{
18
	global $context, $options, $txt, $scripturl, $modSettings, $counter;
19
	global $settings;
20
21
	// Start the javascript... and boy is there a lot.
22
	echo '
23
		<script>';
24
25
	// When using Go Back due to fatal_error, allow the form to be re-submitted with changes.
26
	if (isBrowser('is_firefox'))
27
		echo '
28
			window.addEventListener("pageshow", reActivate, false);';
29
30
	// Start with message icons - and any missing from this theme.
31
	echo '
32
			var icon_urls = {';
33
34
	foreach ($context['icons'] as $icon)
35
		echo '
36
				\'', $icon['value'], '\': \'', $icon['url'], '\'', $icon['is_last'] ? '' : ',';
37
38
	echo '
39
			};';
40
41
	// If this is a poll - use some javascript to ensure the user doesn't create a poll with illegal option combinations.
42
	if ($context['make_poll'])
43
		echo '
44
			var pollOptionNum = 0, pollTabIndex;
45
			var pollOptionId = ', $context['last_choice_id'], ';
46
			function addPollOption()
47
			{
48
				if (pollOptionNum == 0)
49
				{
50
					for (var i = 0, n = document.forms.postmodify.elements.length; i < n; i++)
51
						if (document.forms.postmodify.elements[i].id.substr(0, 8) == \'options-\')
52
						{
53
							pollOptionNum++;
54
							pollTabIndex = document.forms.postmodify.elements[i].tabIndex;
55
						}
56
				}
57
				pollOptionNum++
58
				pollOptionId++
59
60
				setOuterHTML(document.getElementById(\'pollMoreOptions\'), ', JavaScriptEscape('<dt><label for="options-'), ' + pollOptionId + ', JavaScriptEscape('">' . $txt['option'] . ' '), ' + pollOptionNum + ', JavaScriptEscape('</label>:</dt><dd><input type="text" name="options['), ' + pollOptionId + ', JavaScriptEscape(']" id="options-'), ' + pollOptionId + ', JavaScriptEscape('" value="" size="80" maxlength="255" tabindex="'), ' + pollTabIndex + ', JavaScriptEscape('"></dd><p id="pollMoreOptions"></p>'), ');
61
			}';
62
63
	// If we are making a calendar event we want to ensure we show the current days in a month etc... this is done here.
64
	if ($context['make_event'])
65
		echo '
66
			var monthLength = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];';
67
68
	// End of the javascript, start the form and display the link tree.
69
	echo '
70
		</script>
71
		<form action="', $scripturl, '?action=', $context['destination'], ';', empty($context['current_board']) ? '' : 'board=' . $context['current_board'], '" method="post" accept-charset="', $context['character_set'], '" name="postmodify" id="postmodify" class="flow_hidden" onsubmit="', ($context['becomes_approved'] ? '' : 'alert(\'' . $txt['js_post_will_require_approval'] . '\');'), 'submitonce(this);" enctype="multipart/form-data">';
72
73
	// If the user wants to see how their message looks - the preview section is where it's at!
74
	echo '
75
			<div id="preview_section"', isset($context['preview_message']) ? '' : ' style="display: none;"', '>
76
				<div class="cat_bar">
77
					<h3 class="catbg">
78
						<span id="preview_subject">', empty($context['preview_subject']) ? '&nbsp;' : $context['preview_subject'], '</span>
79
					</h3>
80
				</div>
81
				<div id="preview_body" class="windowbg">
82
					', empty($context['preview_message']) ? '<br>' : $context['preview_message'], '
83
				</div>
84
			</div>
85
			<br>';
86
87
	if ($context['make_event'] && (!$context['event']['new'] || !empty($context['current_board'])))
88
		echo '
89
			<input type="hidden" name="eventid" value="', $context['event']['id'], '">';
90
91
	// Start the main table.
92
	echo '
93
			<div class="cat_bar">
94
				<h3 class="catbg">', $context['page_title'], '</h3>
95
			</div>
96
			<div id="post_area">
97
				<div class="roundframe noup">', isset($context['current_topic']) ? '
98
					<input type="hidden" name="topic" value="' . $context['current_topic'] . '">' : '';
99
100
	// If an error occurred, explain what happened.
101
	echo '
102
					<div class="', empty($context['error_type']) || $context['error_type'] != 'serious' ? 'noticebox' : 'errorbox', '"', empty($context['post_error']) ? ' style="display: none"' : '', ' id="errors">
103
						<dl>
104
							<dt>
105
								<strong id="error_serious">', $txt['error_while_submitting'], '</strong>
106
							</dt>
107
							<dd class="error" id="error_list">
108
								', empty($context['post_error']) ? '' : implode('<br>', $context['post_error']), '
109
							</dd>
110
						</dl>
111
					</div>';
112
113
	// If this won't be approved let them know!
114
	if (!$context['becomes_approved'])
115
		echo '
116
					<div class="noticebox">
117
						<em>', $txt['wait_for_approval'], '</em>
118
						<input type="hidden" name="not_approved" value="1">
119
					</div>';
120
121
	// If it's locked, show a message to warn the replier.
122
	if (!empty($context['locked']))
123
		echo '
124
					<div class="errorbox">
125
						', $txt['topic_locked_no_reply'], '
126
					</div>';
127
128
	if (!empty($modSettings['drafts_post_enabled']))
129
		echo '
130
					<div id="draft_section" class="infobox"', isset($context['draft_saved']) ? '' : ' style="display: none;"', '>',
131
						sprintf($txt['draft_saved'], $scripturl . '?action=profile;u=' . $context['user']['id'] . ';area=showdrafts'), '
132
						', (!empty($modSettings['drafts_keep_days']) ? ' <strong>' . sprintf($txt['draft_save_warning'], $modSettings['drafts_keep_days']) . '</strong>' : ''), '
133
					</div>';
134
135
	// The post header... important stuff
136
	template_post_header();
137
138
	// Are you posting a calendar event?
139
	if ($context['make_event'])
140
	{
141
		// Note to theme writers: The JavaScripts expect the input fields for the start and end dates & times to be contained in a wrapper element with the id "event_time_input"
142
		echo '
143
					<hr class="clear">
144
					<div id="post_event">
145
						<fieldset id="event_options">
146
							<legend', isset($context['post_error']['no_event']) ? ' class="error"' : '', '>', $txt['calendar_event_options'], '</legend>
147
							<input type="hidden" name="calendar" value="1">
148
							<div class="event_options" id="event_title">
149
								<div>
150
									<span class="label">', $txt['calendar_event_title'], '</span>
151
									<input type="text" id="evtitle" name="evtitle" maxlength="255" value="', $context['event']['title'], '" tabindex="', $context['tabindex']++, '">
152
								</div>
153
							</div>
154
							<div class="event_options">
155
								<div class="event_options_left" id="event_time_input">
156
									<div>
157
										<span class="label">', $txt['start'], '</span>
158
										<input type="text" name="start_date" id="start_date" value="', trim($context['event']['start_date_orig']), '" tabindex="', $context['tabindex']++, '" class="date_input start" data-type="date">
159
										<input type="text" name="start_time" id="start_time" maxlength="11" value="', $context['event']['start_time_orig'], '" tabindex="', $context['tabindex']++, '" class="time_input start" data-type="time"', !empty($context['event']['allday']) ? ' disabled' : '', '>
160
									</div>
161
									<div>
162
										<span class="label">', $txt['end'], '</span>
163
										<input type="text" name="end_date" id="end_date" value="', trim($context['event']['end_date_orig']), '" tabindex="', $context['tabindex']++, '" class="date_input end" data-type="date"', $modSettings['cal_maxspan'] == 1 ? ' disabled' : '', '>
164
										<input type="text" name="end_time" id="end_time" maxlength="11" value="', $context['event']['end_time_orig'], '" tabindex="', $context['tabindex']++, '" class="time_input end" data-type="time"', !empty($context['event']['allday']) ? ' disabled' : '', '>
165
									</div>
166
								</div>
167
								<div class="event_options_right" id="event_time_options">
168
									<div id="event_allday">
169
										<label for="allday"><span class="label">', $txt['calendar_allday'], '</span></label>
170
										<input type="checkbox" name="allday" id="allday"', !empty($context['event']['allday']) ? ' checked' : '', ' tabindex="', $context['tabindex']++, '">
171
									</div>
172
									<div id="event_timezone">
173
										<span class="label">', $txt['calendar_timezone'], '</span>
174
										<select name="tz" id="tz"', !empty($context['event']['allday']) ? ' disabled' : '', '>';
175
176
			foreach ($context['all_timezones'] as $tz => $tzname)
177
				echo '
178
											<option', is_numeric($tz) ? ' value="" disabled' : ' value="' . $tz . '"', $tz === $context['event']['tz'] ? ' selected' : '', '>', $tzname, '</option>';
179
180
			echo '
181
										</select>
182
									</div>
183
								</div>
184
							</div>
185
							<div class="event_options">
186
								<div>
187
									<span class="label">', $txt['location'], '</span>
188
									<input type="text" name="event_location" id="event_location" maxlength="255" value="', $context['event']['location'], '" tabindex="', $context['tabindex']++, '">
189
								</div>
190
							</div>
191
						</fieldset>
192
					</div><!-- #post_event -->';
193
	}
194
195
	// If this is a poll then display all the poll options!
196
	if ($context['make_poll'])
197
	{
198
		echo '
199
					<hr class="clear">
200
					<div id="edit_poll">
201
						<fieldset id="poll_main">
202
							<legend><span ', (isset($context['poll_error']['no_question']) ? ' class="error"' : ''), '>', $txt['poll_question'], '</span></legend>
203
							<dl class="settings poll_options">
204
								<dt>', $txt['poll_question'], '</dt>
205
								<dd>
206
									<input type="text" name="question" value="', isset($context['question']) ? $context['question'] : '', '" tabindex="', $context['tabindex']++, '" size="80">
207
								</dd>';
208
209
		// Loop through all the choices and print them out.
210
		foreach ($context['choices'] as $choice)
211
			echo '
212
								<dt>
213
									<label for="options-', $choice['id'], '">', $txt['option'], ' ', $choice['number'], '</label>:
214
								</dt>
215
								<dd>
216
									<input type="text" name="options[', $choice['id'], ']" id="options-', $choice['id'], '" value="', $choice['label'], '" tabindex="', $context['tabindex']++, '" size="80" maxlength="255">
217
								</dd>';
218
219
		echo '
220
								<p id="pollMoreOptions"></p>
221
							</dl>
222
							<strong><a href="javascript:addPollOption(); void(0);">(', $txt['poll_add_option'], ')</a></strong>
223
						</fieldset>
224
						<fieldset id="poll_options">
225
							<legend>', $txt['poll_options'], '</legend>
226
							<dl class="settings poll_options">
227
								<dt>
228
									<label for="poll_max_votes">', $txt['poll_max_votes'], ':</label>
229
								</dt>
230
								<dd>
231
									<input type="text" name="poll_max_votes" id="poll_max_votes" size="2" value="', $context['poll_options']['max_votes'], '">
232
								</dd>
233
								<dt>
234
									<label for="poll_expire">', $txt['poll_run'], ':</label><br>
235
									<em class="smalltext">', $txt['poll_run_limit'], '</em>
236
								</dt>
237
								<dd>
238
									<input type="text" name="poll_expire" id="poll_expire" size="2" value="', $context['poll_options']['expire'], '" onchange="pollOptions();" maxlength="4"> ', $txt['days_word'], '
239
								</dd>
240
								<dt>
241
									<label for="poll_change_vote">', $txt['poll_do_change_vote'], ':</label>
242
								</dt>
243
								<dd>
244
									<input type="checkbox" id="poll_change_vote" name="poll_change_vote"', !empty($context['poll']['change_vote']) ? ' checked' : '', '>
245
								</dd>';
246
247
		if ($context['poll_options']['guest_vote_enabled'])
248
			echo '
249
								<dt>
250
									<label for="poll_guest_vote">', $txt['poll_guest_vote'], ':</label>
251
								</dt>
252
								<dd>
253
									<input type="checkbox" id="poll_guest_vote" name="poll_guest_vote"', !empty($context['poll_options']['guest_vote']) ? ' checked' : '', '>
254
								</dd>';
255
256
		echo '
257
								<dt>
258
									', $txt['poll_results_visibility'], ':
259
								</dt>
260
								<dd>
261
									<input type="radio" name="poll_hide" id="poll_results_anyone" value="0"', $context['poll_options']['hide'] == 0 ? ' checked' : '', '> <label for="poll_results_anyone">', $txt['poll_results_anyone'], '</label><br>
262
									<input type="radio" name="poll_hide" id="poll_results_voted" value="1"', $context['poll_options']['hide'] == 1 ? ' checked' : '', '> <label for="poll_results_voted">', $txt['poll_results_voted'], '</label><br>
263
									<input type="radio" name="poll_hide" id="poll_results_expire" value="2"', $context['poll_options']['hide'] == 2 ? ' checked' : '', empty($context['poll_options']['expire']) ? ' disabled' : '', '> <label for="poll_results_expire">', $txt['poll_results_after'], '</label>
264
								</dd>
265
							</dl>
266
						</fieldset>
267
					</div><!-- #edit_poll -->';
268
	}
269
270
	// Show the actual posting area...
271
	echo '
272
					', template_control_richedit($context['post_box_name'], 'smileyBox_message', 'bbcBox_message');
0 ignored issues
show
'smileyBox_message' of type string is incompatible with the type boolean|null expected by parameter $smileyContainer of template_control_richedit(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

272
					', template_control_richedit($context['post_box_name'], /** @scrutinizer ignore-type */ 'smileyBox_message', 'bbcBox_message');
Loading history...
'bbcBox_message' of type string is incompatible with the type boolean|null expected by parameter $bbcContainer of template_control_richedit(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

272
					', template_control_richedit($context['post_box_name'], 'smileyBox_message', /** @scrutinizer ignore-type */ 'bbcBox_message');
Loading history...
Are you sure the usage of template_control_richedi...age', 'bbcBox_message') is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
273
274
	// Show attachments.
275
	if (!empty($context['current_attachments']) || $context['can_post_attachment'])
276
	{
277
		echo '
278
					<div id="post_attachments_area" class="roundframe noup">';
279
280
		// The non-JavaScript UI.
281
		echo '
282
							<div id="postAttachment">
283
								<div class="padding">
284
									<div>
285
										<strong>', $txt['attachments'], '</strong>:';
286
287
		if ($context['can_post_attachment'])
288
			echo '
289
										<input type="file" multiple="multiple" name="attachment[]" id="attachment1">
290
										<a href="javascript:void(0);" onclick="cleanFileInput(\'attachment1\');">(', $txt['clean_attach'], ')</a>';
291
292
		if (!empty($modSettings['attachmentSizeLimit']))
293
			echo '
294
										<input type="hidden" name="MAX_FILE_SIZE" value="' . $modSettings['attachmentSizeLimit'] * 1024 . '">';
295
296
		echo '
297
									</div>';
298
299
		if (!empty($context['attachment_restrictions']))
300
			echo '
301
									<div class="smalltext">', $txt['attach_restrictions'], ' ', implode(', ', $context['attachment_restrictions']), '</div>';
302
303
		echo '
304
									<div class="smalltext">
305
										<input type="hidden" name="attach_del[]" value="0">
306
										', $txt['uncheck_unwatchd_attach'], '
307
									</div>
308
								</div>
309
								<div class="attachments">';
310
311
		// If this post already has attachments on it - give information about them.
312
		if (!empty($context['current_attachments']))
313
		{
314
			foreach ($context['current_attachments'] as $attachment)
315
			{
316
				echo '
317
									<div class="attached">
318
										<input type="checkbox" id="attachment_', $attachment['attachID'], '" name="attach_del[]" value="', $attachment['attachID'], '"', empty($attachment['unchecked']) ? ' checked' : '', '>';
319
320
				if (!empty($modSettings['attachmentShowImages']))
321
				{
322
					if (strpos($attachment['mime_type'], 'image') === 0)
323
						$src = $scripturl . '?action=dlattach;attach=' . (!empty($attachment['thumb']) ? $attachment['thumb'] : $attachment['attachID']) . ';preview;image';
324
					else
325
						$src = $settings['images_url'] . '/generic_attach.png';
326
327
					echo '
328
										<div class="attachments_top">
329
											<img src="', $src, '" alt="" loading="lazy" class="atc_img">
330
										</div>';
331
				}
332
333
				echo '
334
										<div class="attachments_bot">
335
											<span class="name">' . $attachment['name'] . '</span>', (empty($attachment['approved']) ? '
336
											<br>(' . $txt['awaiting_approval'] . ')' : ''), '
337
											<br>', $attachment['size'] < 1024000 ? round($attachment['size'] / 1024, 2) . ' ' . $txt['kilobyte'] : round($attachment['size'] / 1024 / 1024, 2) . ' ' . $txt['megabyte'], '
338
										</div>
339
									</div>';
340
			}
341
		}
342
343
		echo '
344
								</div>
345
							</div>';
346
347
		if (!empty($context['files_in_session_warning']))
348
			echo '
349
							<div class="smalltext"><em>', $context['files_in_session_warning'], '</em></div>';
350
351
		// Is the user allowed to post any additional ones? If so give them the boxes to do it!
352
		if ($context['can_post_attachment'])
353
		{
354
			// Print dropzone UI.
355
			echo '
356
						<div id="attachment_upload">
357
							<div id="drop_zone_ui" class="centertext">
358
								<div class="attach_drop_zone_label">
359
									', $context['num_allowed_attachments'] <= count($context['current_attachments']) ? $txt['attach_limit_nag'] : $txt['attach_drop_zone'], '
360
								</div>
361
							</div>
362
							<div class="files" id="attachment_previews">
363
								<div id="au-template">
364
									<div class="attachment_preview_wrapper">
365
										<div class="attach-ui roundframe">
366
											<a data-dz-remove class="main_icons delete floatright cancel"></a>
367
											<div class="attached_BBC_width_height">
368
												<div class="attached_BBC_width">
369
													<label for="attached_BBC_width">', $txt['attached_insert_width'], '</label>
370
													<input type="number" name="attached_BBC_width" min="0" value="" placeholder="', $txt['attached_insert_placeholder'], '">
371
												</div>
372
												<div class="attached_BBC_height">
373
													<label for="attached_BBC_height">', $txt['attached_insert_height'], '</label>
374
													<input type="number" name="attached_BBC_height" min="0" value="" placeholder="', $txt['attached_insert_placeholder'], '">
375
												</div>
376
											</div>
377
										</div>
378
										<div class="attach-preview">
379
											<img data-dz-thumbnail />
380
										</div>
381
										<div class="attachment_info">
382
											<span class="name" data-dz-name></span>
383
											<span class="error" data-dz-errormessage></span>
384
											<span class="size" data-dz-size></span>
385
											<span class="message" data-dz-message></span>
386
											<div class="progress_bar" role="progressBar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
387
												<div class="bar"></div>
388
											</div>
389
										</div><!-- .attachment_info -->
390
									</div>
391
								</div><!-- #au-template -->
392
								<div class="attachment_spacer">
393
									<div class="fallback">
394
											<input type="file" multiple="multiple" name="attachment[]" id="attachment1" class="fallback"> (<a href="javascript:void(0);" onclick="cleanFileInput(\'attachment1\');">', $txt['clean_attach'], '</a>)';
395
396
			if (!empty($modSettings['attachmentSizeLimit']))
397
				echo '
398
											<input type="hidden" name="MAX_FILE_SIZE" value="' . $modSettings['attachmentSizeLimit'] * 1024 . '">';
399
400
			echo '
401
									</div><!-- .fallback -->
402
								</div>
403
							</div><!-- #attachment_previews -->
404
						</div>
405
						<div id="max_files_progress" class="max_files_progress progress_bar" role="progressBar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
406
							<div class="bar"></div>
407
							<div id="max_files_progress_text"></div>
408
						</div>';
409
		}
410
411
		echo '
412
					</div>';
413
	}
414
415
	// If the admin has enabled the hiding of the additional options - show a link and image for it.
416
	if (!empty($modSettings['additional_options_collapsable']))
417
		echo '
418
					<div id="post_additional_options_header">
419
						<strong><a href="#" id="postMoreExpandLink"> ', $txt['post_additionalopt'], '</a></strong>
420
					</div>';
421
422
	echo '
423
					<div id="post_additional_options">';
424
425
	// Display the checkboxes for all the standard options - if they are available to the user!
426
	echo '
427
						<div id="post_settings" class="smalltext">
428
							<ul class="post_options">
429
								', $context['can_notify'] ? '<li><input type="hidden" name="notify" value="0"><label for="check_notify"><input type="checkbox" name="notify" id="check_notify"' . ($context['notify'] || !empty($options['auto_notify']) || $context['auto_notify'] ? ' checked' : '') . ' value="1"> ' . $txt['notify_replies'] . '</label></li>' : '', '
430
								', $context['can_lock'] ? '<li><input type="hidden" name="already_locked" value="' . $context['already_locked'] . '"><input type="hidden" name="lock" value="0"><label for="check_lock"><input type="checkbox" name="lock" id="check_lock"' . ($context['locked'] ? ' checked' : '') . ' value="1"> ' . $txt['lock_topic'] . '</label></li>' : '', '
431
								<li><label for="check_back"><input type="checkbox" name="goback" id="check_back"' . ($context['back_to_topic'] || !empty($options['return_to_post']) ? ' checked' : '') . ' value="1"> ' . $txt['back_to_topic'] . '</label></li>
432
								', $context['can_sticky'] ? '<li><input type="hidden" name="already_sticky" value="' . $context['already_sticky'] . '"><input type="hidden" name="sticky" value="0"><label for="check_sticky"><input type="checkbox" name="sticky" id="check_sticky"' . ($context['sticky'] ? ' checked' : '') . ' value="1"> ' . $txt['sticky_after_posting'] . '</label></li>' : '', '
433
								<li><label for="check_smileys"><input type="checkbox" name="ns" id="check_smileys"', $context['use_smileys'] ? '' : ' checked', ' value="NS"> ', $txt['dont_use_smileys'], '</label></li>', '
434
								', $context['can_move'] ? '<li><input type="hidden" name="move" value="0"><label for="check_move"><input type="checkbox" name="move" id="check_move" value="1"' . (!empty($context['move']) ? ' checked" ' : '') . '> ' . $txt['move_after_posting'] . '</label></li>' : '', '
435
								', $context['can_announce'] && $context['is_first_post'] ? '<li><label for="check_announce"><input type="checkbox" name="announce_topic" id="check_announce" value="1"' . (!empty($context['announce']) ? ' checked' : '') . '> ' . $txt['announce_topic'] . '</label></li>' : '', '
436
								', $context['show_approval'] ? '<li><label for="approve"><input type="checkbox" name="approve" id="approve" value="2"' . ($context['show_approval'] === 2 ? ' checked' : '') . '> ' . $txt['approve_this_post'] . '</label></li>' : '', '
437
							</ul>
438
						</div><!-- #post_settings -->';
439
440
	echo '
441
					</div><!-- #post_additional_options -->';
442
443
	// If the admin enabled the drafts feature, show a draft selection box
444
	if (!empty($modSettings['drafts_post_enabled']) && !empty($context['drafts']) && !empty($modSettings['drafts_show_saved_enabled']) && !empty($options['drafts_show_saved_enabled']))
445
	{
446
		echo '
447
					<div id="post_draft_options_header" class="title_bar">
448
						<h4 class="titlebg">
449
							<span id="postDraftExpand" class="toggle_up floatright" style="display: none;"></span> <strong><a href="#" id="postDraftExpandLink">', $txt['drafts_show'], '</a></strong>
450
						</h4>
451
					</div>
452
					<div id="post_draft_options">
453
						<dl class="settings">
454
							<dt><strong>', $txt['subject'], '</strong></dt>
455
							<dd><strong>', $txt['draft_saved_on'], '</strong></dd>';
456
457
		foreach ($context['drafts'] as $draft)
458
			echo '
459
							<dt>', $draft['link'], '</dt>
460
							<dd>', $draft['poster_time'], '</dd>';
461
		echo '
462
						</dl>
463
					</div>';
464
	}
465
466
	// Is visual verification enabled?
467
	if ($context['require_verification'])
468
		echo '
469
					<div class="post_verification">
470
						<span', !empty($context['post_error']['need_qr_verification']) ? ' class="error"' : '', '>
471
							<strong>', $txt['verification'], ':</strong>
472
						</span>
473
						', template_control_verification($context['visual_verification_id'], 'all'), '
474
					</div>';
475
476
	// Finally, the submit buttons.
477
	echo '
478
					<span id="post_confirm_buttons">
479
						', template_control_richedit_buttons($context['post_box_name']);
0 ignored issues
show
Are you sure the usage of template_control_richedi...ntext['post_box_name']) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
480
481
	// Option to delete an event if user is editing one.
482
	if ($context['make_event'] && !$context['event']['new'])
483
		echo '
484
						<input type="submit" name="deleteevent" value="', $txt['event_delete'], '" data-confirm="', $txt['event_delete_confirm'], '" class="button you_sure">';
485
486
	echo '
487
					</span>
488
				</div><!-- .roundframe -->
489
			</div><!-- #post_area -->
490
			<br class="clear">';
491
492
	// Assuming this isn't a new topic pass across the last message id.
493
	if (isset($context['topic_last_message']))
494
		echo '
495
			<input type="hidden" name="last_msg" value="', $context['topic_last_message'], '">';
496
497
	echo '
498
			<input type="hidden" name="additional_options" id="additional_options" value="', $context['show_additional_options'] ? '1' : '0', '">
499
			<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
500
			<input type="hidden" name="seqnum" value="', $context['form_sequence_number'], '">
501
		</form>';
502
503
	echo '
504
		<script>';
505
506
	$newPostsHTML = '
507
		<span id="new_replies"></span>
508
		<div class="windowbg">
509
			<div id="msg%PostID%">
510
			<h5 class="floatleft">
511
				<span>' . $txt['posted_by'] . '</span>
512
				%PosterName%
513
			</h5>
514
			&nbsp;-&nbsp;%PostTime%&nbsp;&#187; <span class="new_posts" id="image_new_%PostID%">' . $txt['new'] . '</span>
515
			<br class="clear">
516
			<div id="msg_%PostID%_ignored_prompt" class="smalltext" style="display: none;">' . $txt['ignoring_user'] . '<a href="#" id="msg_%PostID%_ignored_link" style="%IgnoredStyle%">' . $txt['show_ignore_user_post'] . '</a></div>
517
			<div class="list_posts smalltext" id="msg_%PostID%_body">%PostBody%</div>';
518
519
	if ($context['can_quote'])
520
		$newPostsHTML .= '
521
			<ul class="quickbuttons sf-js-enabled sf-arrows" id="msg_%PostID%_quote" style="touch-action: pan-y;">
522
				<li id="post_modify">
523
					<a href="#postmodify" onclick="return insertQuoteFast(%PostID%);" class="quote_button"><span class="main_icons quote"></span>' . $txt['quote'] . '</a>
524
				</li>
525
			</ul>';
526
527
	$newPostsHTML .= '
528
		</div>';
529
530
	// The functions used to preview a posts without loading a new page.
531
	echo '
532
			var oPreviewPost = new smc_preview_post({
533
				sPreviewSectionContainerID: "preview_section",
534
				sPreviewSubjectContainerID: "preview_subject",
535
				sPreviewBodyContainerID: "preview_body",
536
				sErrorsContainerID: "errors",
537
				sErrorsSeriousContainerID: "error_serious",
538
				sErrorsListContainerID: "error_list",
539
				sCaptionContainerID: "caption_%ID%",
540
				sNewImageContainerID: "image_new_%ID%",
541
				sPostBoxContainerID: ', JavaScriptEscape($context['post_box_name']), ',
542
				bMakePoll: ', $context['make_poll'] ? 'true' : 'false', ',
543
				sTxtPreviewTitle: ', JavaScriptEscape($txt['preview_title']), ',
544
				sTxtPreviewFetch: ', JavaScriptEscape($txt['preview_fetch']), ',
545
				sSessionVar: ', JavaScriptEscape($context['session_var']), ',
546
				newPostsTemplate:', JavaScriptEscape($newPostsHTML);
547
548
	if (!empty($context['current_board']))
549
		echo ',
550
				iCurrentBoard: ', $context['current_board'], '';
551
552
	echo '
553
			});';
554
555
	// Code for showing and hiding additional options.
556
	if (!empty($modSettings['additional_options_collapsable']))
557
		echo '
558
			var oSwapAdditionalOptions = new smc_Toggle({
559
				bToggleEnabled: true,
560
				bCurrentlyCollapsed: ', $context['show_additional_options'] ? 'false' : 'true', ',
561
				funcOnBeforeCollapse: function () {
562
					document.getElementById(\'additional_options\').value = \'0\';
563
				},
564
				funcOnBeforeExpand: function () {
565
					document.getElementById(\'additional_options\').value = \'1\';
566
				},
567
				aSwappableContainers: [
568
					\'post_additional_options\',
569
				],
570
				aSwapImages: [
571
					{
572
						sId: \'postMoreExpandLink\',
573
						altExpanded: \'-\',
574
						altCollapsed: \'+\'
575
					}
576
				],
577
				aSwapLinks: [
578
					{
579
						sId: \'postMoreExpandLink\',
580
						msgExpanded: ', JavaScriptEscape($txt['post_additionalopt']), ',
581
						msgCollapsed: ', JavaScriptEscape($txt['post_additionalopt']), '
582
					}
583
				]
584
			});';
585
586
	// Code for showing and hiding drafts
587
	if (!empty($context['drafts']))
588
		echo '
589
			var oSwapDraftOptions = new smc_Toggle({
590
				bToggleEnabled: true,
591
				bCurrentlyCollapsed: true,
592
				aSwappableContainers: [
593
					\'post_draft_options\',
594
				],
595
				aSwapImages: [
596
					{
597
						sId: \'postDraftExpand\',
598
						altExpanded: \'-\',
599
						altCollapsed: \'+\'
600
					}
601
				],
602
				aSwapLinks: [
603
					{
604
						sId: \'postDraftExpandLink\',
605
						msgExpanded: ', JavaScriptEscape($txt['draft_hide']), ',
606
						msgCollapsed: ', JavaScriptEscape($txt['drafts_show']), '
607
					}
608
				]
609
			});';
610
611
	echo '
612
			var oEditorID = "', $context['post_box_name'], '";
613
			var oEditorObject = oEditorHandle_', $context['post_box_name'], ';
614
		</script>';
615
616
	// If the user is replying to a topic show the previous posts.
617
	if (isset($context['previous_posts']) && count($context['previous_posts']) > 0)
618
	{
619
		echo '
620
		<div id="recent" class="flow_hidden main_section">
621
			<div class="cat_bar cat_bar_round">
622
				<h3 class="catbg">', $txt['topic_summary'], '</h3>
623
			</div>
624
			<span id="new_replies"></span>';
625
626
		$ignored_posts = array();
627
		foreach ($context['previous_posts'] as $post)
628
		{
629
			$ignoring = false;
630
			if (!empty($post['is_ignored']))
631
				$ignored_posts[] = $ignoring = $post['id'];
632
633
			echo '
634
			<div class="windowbg">
635
				<div id="msg', $post['id'], '">
636
					<div>
637
						<h5 class="floatleft">
638
							<span>', $txt['posted_by'], '</span> ', $post['poster'], '
639
						</h5>
640
						<span class="smalltext">&nbsp;-&nbsp;', $post['time'], '</span>
641
					</div>';
642
643
			if ($ignoring)
644
				echo '
645
					<div id="msg_', $post['id'], '_ignored_prompt" class="smalltext">
646
						', $txt['ignoring_user'], '
647
						<a href="#" id="msg_', $post['id'], '_ignored_link" style="display: none;">', $txt['show_ignore_user_post'], '</a>
648
					</div>';
649
650
			echo '
651
					<div class="list_posts smalltext" id="msg_', $post['id'], '_body" data-msgid="', $post['id'], '">', $post['message'], '</div>';
652
653
			if ($context['can_quote'])
654
				echo '
655
					<ul class="quickbuttons" id="msg_', $post['id'], '_quote">
656
						<li style="display:none;" id="quoteSelected_', $post['id'], '" data-msgid="', $post['id'], '"><a href="javascript:void(0)"><span class="main_icons quote_selected"></span>', $txt['quote_selected_action'], '</a></li>
657
						<li id="post_modify"><a href="#postmodify" onclick="return insertQuoteFast(', $post['id'], ');"><span class="main_icons quote"></span>', $txt['quote'], '</a></li>
658
					</ul>';
659
660
			echo '
661
				</div><!-- #msg[id] -->
662
			</div><!-- .windowbg -->';
663
		}
664
665
		echo '
666
		</div><!-- #recent -->
667
		<script>
668
			var aIgnoreToggles = new Array();';
669
670
		foreach ($ignored_posts as $post_id)
671
		{
672
			echo '
673
			aIgnoreToggles[', $post_id, '] = new smc_Toggle({
674
				bToggleEnabled: true,
675
				bCurrentlyCollapsed: true,
676
				aSwappableContainers: [
677
					\'msg_', $post_id, '_body\',
678
					\'msg_', $post_id, '_quote\',
679
				],
680
				aSwapLinks: [
681
					{
682
						sId: \'msg_', $post_id, '_ignored_link\',
683
						msgExpanded: \'\',
684
						msgCollapsed: ', JavaScriptEscape($txt['show_ignore_user_post']), '
685
					}
686
				]
687
			});';
688
		}
689
690
		echo '
691
			function insertQuoteFast(messageid)
692
			{
693
				var e = document.getElementById("', $context['post_box_name'], '");
694
				sceditor.instance(e).insertQuoteFast(messageid);
695
696
				return true;
697
			}
698
			function onReceiveOpener(text)
699
			{
700
				var e = document.getElementById("', $context['post_box_name'], '");
701
				sceditor.instance(e).insert(text);
702
			}
703
		</script>';
704
	}
705
}
706
707
/**
708
 * The template for the spellchecker.
709
 */
710
function template_spellcheck()
711
{
712
	global $context, $settings, $txt, $modSettings;
713
714
	// The style information that makes the spellchecker look... like the forum hopefully!
715
	echo '<!DOCTYPE html>
716
<html', $context['right_to_left'] ? ' dir="rtl"' : '', '>
717
	<head>
718
		<meta charset="', $context['character_set'], '">
719
		<title>', $txt['spell_check'], '</title>
720
		<link rel="stylesheet" href="', $settings['theme_url'], '/css/index', $context['theme_variant'], '.css', $context['browser_cache'], '">
721
		<style>
722
			body, td {
723
				font-size: small;
724
				margin: 0;
725
				background: #f0f0f0;
726
				color: #000;
727
				padding: 10px;
728
			}
729
			.highlight {
730
				color: red;
731
				font-weight: bold;
732
			}
733
			#spellview {
734
				border-style: outset;
735
				border: 1px solid black;
736
				padding: 5px;
737
				width: 95%;
738
				height: 314px;
739
				overflow: auto;
740
				background: #ffffff;
741
			}';
742
743
	// As you may expect - we need a lot of javascript for this... load it from the separate files.
744
	echo '
745
		</style>
746
		<script>
747
			var spell_formname = window.opener.spell_formname;
748
			var spell_fieldname = window.opener.spell_fieldname;
749
		</script>
750
		<script src="', $settings['default_theme_url'], '/scripts/spellcheck.js', $context['browser_cache'], '"></script>
751
		<script src="', $settings['default_theme_url'], '/scripts/script.js', $context['browser_cache'], '"></script>
752
		<script>
753
			', $context['spell_js'], '
754
		</script>
755
	</head>
756
	<body onload="nextWord(false);">
757
		<form action="#" method="post" accept-charset="', $context['character_set'], '" name="spellingForm" id="spellingForm" onsubmit="return false;">
758
			<div id="spellview">&nbsp;</div>
759
			<table width="100%">
760
				<tr class="windowbg">
761
					<td style="width: 50%; vertical-align: top">
762
						', $txt['spellcheck_change_to'], '<br>
763
						<input type="text" name="changeto" style="width: 98%;">
764
					</td>
765
					<td style="width: 50%">
766
						', $txt['spellcheck_suggest'], '<br>
767
						<select name="suggestions" style="width: 98%;" size="5" onclick="if (this.selectedIndex != -1) this.form.changeto.value = this.options[this.selectedIndex].text;" ondblclick="replaceWord();">
768
						</select>
769
					</td>
770
				</tr>
771
			</table>
772
			<div class="righttext" style="padding: 4px;">
773
				<input type="button" name="change" value="', $txt['spellcheck_change'], '" onclick="replaceWord();" class="button">
774
				<input type="button" name="changeall" value="', $txt['spellcheck_change_all'], '" onclick="replaceAll();" class="button">
775
				<input type="button" name="ignore" value="', $txt['spellcheck_ignore'], '" onclick="nextWord(false);" class="button">
776
				<input type="button" name="ignoreall" value="', $txt['spellcheck_ignore_all'], '" onclick="nextWord(true);" class="button">
777
			</div>
778
		</form>
779
	</body>
780
</html>';
781
}
782
783
/**
784
 * The template for the AJAX quote feature
785
 */
786
function template_quotefast()
787
{
788
	global $context, $settings, $txt, $modSettings;
789
790
	echo '<!DOCTYPE html>
791
<html', $context['right_to_left'] ? ' dir="rtl"' : '', '>
792
	<head>
793
		<meta charset="', $context['character_set'], '">
794
		<title>', $txt['retrieving_quote'], '</title>
795
		<script src="', $settings['default_theme_url'], '/scripts/script.js', $context['browser_cache'], '"></script>
796
	</head>
797
	<body>
798
		', $txt['retrieving_quote'], '
799
		<div id="temporary_posting_area" style="display: none;"></div>
800
		<script>';
801
802
	if ($context['close_window'])
803
		echo '
804
			window.close();';
805
	else
806
	{
807
		// Lucky for us, Internet Explorer has an "innerText" feature which basically converts entities <--> text. Use it if possible ;)
808
		echo '
809
			var quote = \'', $context['quote']['text'], '\';
810
			var stage = \'createElement\' in document ? document.createElement("DIV") : document.getElementById("temporary_posting_area");
811
812
			if (\'DOMParser\' in window && !(\'opera\' in window))
813
			{
814
				var xmldoc = new DOMParser().parseFromString("<temp>" + \'', $context['quote']['mozilla'], '\'.replace(/\n/g, "_SMF-BREAK_").replace(/\t/g, "_SMF-TAB_") + "</temp>", "text/xml");
815
				quote = xmldoc.childNodes[0].textContent.replace(/_SMF-BREAK_/g, "\n").replace(/_SMF-TAB_/g, "\t");
816
			}
817
			else if (\'innerText\' in stage)
818
			{
819
				setInnerHTML(stage, quote.replace(/\n/g, "_SMF-BREAK_").replace(/\t/g, "_SMF-TAB_").replace(/</g, "&lt;").replace(/>/g, "&gt;"));
820
				quote = stage.innerText.replace(/_SMF-BREAK_/g, "\n").replace(/_SMF-TAB_/g, "\t");
821
			}
822
823
			if (\'opera\' in window)
824
				quote = quote.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, \'"\').replace(/&amp;/g, "&");
825
826
			window.opener.onReceiveOpener(quote);
827
828
			window.focus();
829
			setTimeout("window.close();", 400);';
830
	}
831
	echo '
832
		</script>
833
	</body>
834
</html>';
835
}
836
837
/**
838
 * The form for sending out an announcement
839
 */
840
function template_announce()
841
{
842
	global $context, $txt, $scripturl;
843
844
	echo '
845
	<div id="announcement">
846
		<form action="', $scripturl, '?action=announce;sa=send" method="post" accept-charset="', $context['character_set'], '">
847
			<div class="cat_bar">
848
				<h3 class="catbg">', $txt['announce_title'], '</h3>
849
			</div>
850
			<div class="information">
851
				', $txt['announce_desc'], '
852
			</div>
853
			<div class="windowbg">
854
				<p>
855
					', $txt['announce_this_topic'], ' <a href="', $scripturl, '?topic=', $context['current_topic'], '.0">', $context['topic_subject'], '</a>
856
				</p>
857
				<ul>';
858
859
	foreach ($context['groups'] as $group)
860
		echo '
861
					<li>
862
						<label for="who_', $group['id'], '"><input type="checkbox" name="who[', $group['id'], ']" id="who_', $group['id'], '" value="', $group['id'], '" checked> ', $group['name'], '</label> <em>(', $group['member_count'], ')</em>
863
					</li>';
864
865
	echo '
866
					<li>
867
						<label for="checkall"><input type="checkbox" id="checkall" onclick="invertAll(this, this.form);" checked> <em>', $txt['check_all'], '</em></label>
868
					</li>
869
				</ul>
870
				<hr>
871
				<div id="confirm_buttons">
872
					<input type="submit" value="', $txt['post'], '" class="button">
873
					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
874
					<input type="hidden" name="topic" value="', $context['current_topic'], '">
875
					<input type="hidden" name="move" value="', $context['move'], '">
876
					<input type="hidden" name="goback" value="', $context['go_back'], '">
877
				</div>
878
				<br class="clear_right">
879
			</div><!-- .windowbg -->
880
		</form>
881
	</div><!-- #announcement -->
882
	<br>';
883
}
884
885
/**
886
 * The confirmation/progress page, displayed after the admin has clicked the button to send the announcement.
887
 */
888
function template_announcement_send()
889
{
890
	global $context, $txt, $scripturl;
891
892
	echo '
893
	<div id="announcement">
894
		<form action="', $scripturl, '?action=announce;sa=send" method="post" accept-charset="', $context['character_set'], '" name="autoSubmit" id="autoSubmit">
895
			<div class="windowbg">
896
				<p>
897
					', $txt['announce_sending'], ' <a href="', $scripturl, '?topic=', $context['current_topic'], '.0" target="_blank" rel="noopener">', $context['topic_subject'], '</a>
898
				</p>
899
				<div class="progress_bar">
900
					<span>', $context['percentage_done'], '% ', $txt['announce_done'], '</span>
901
					<div class="bar" style="width: ', $context['percentage_done'], '%;"></div>
902
				</div>
903
				<hr>
904
				<div id="confirm_buttons">
905
					<input type="submit" name="b" value="', $txt['announce_continue'], '" class="button">
906
					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
907
					<input type="hidden" name="topic" value="', $context['current_topic'], '">
908
					<input type="hidden" name="move" value="', $context['move'], '">
909
					<input type="hidden" name="goback" value="', $context['go_back'], '">
910
					<input type="hidden" name="start" value="', $context['start'], '">
911
					<input type="hidden" name="membergroups" value="', $context['membergroups'], '">
912
				</div>
913
				<br class="clear_right">
914
			</div><!-- .windowbg -->
915
		</form>
916
	</div><!-- #announcement -->
917
	<br>
918
	<script>
919
		var countdown = 2;
920
		doAutoSubmit();
921
922
		function doAutoSubmit()
923
		{
924
			if (countdown == 0)
925
				document.forms.autoSubmit.submit();
926
			else if (countdown == -1)
927
				return;
928
929
			document.forms.autoSubmit.b.value = "', $txt['announce_continue'], ' (" + countdown + ")";
930
			countdown--;
931
932
			setTimeout("doAutoSubmit();", 1000);
933
		}
934
	</script>';
935
}
936
937
/**
938
 * Prints the input fields in the form's header (subject, message icon, guest name & email, etc.)
939
 *
940
 * Mod authors can use the 'integrate_post_end' hook to modify or add to these (see Post.php).
941
 *
942
 * Theme authors can customize the output in a couple different ways:
943
 * 1. Change specific values in the $context['posting_fields'] array.
944
 * 2. Add an 'html' element to the 'label' and/or 'input' elements of the field they want to
945
 *    change. This should contain the literal HTML string to be printed.
946
 *
947
 * See the documentation in Post.php for more info on the $context['posting_fields'] array.
948
 */
949
function template_post_header()
950
{
951
	global $context, $txt;
952
953
	// Sanity check: submitting the form won't work without at least a subject field
954
	if (empty($context['posting_fields']['subject']) || !is_array($context['posting_fields']['subject']))
955
	{
956
		$context['posting_fields']['subject'] = array(
957
			'label' => array('html' => '<label for="subject" id="caption_subject">' . $txt['subject'] . '</label>'),
958
			'input' => array('html' => '<input type="text" id="subject" name="subject" value="' . $context['subject'] . '" size="80" maxlength="80" required>')
959
		);
960
	}
961
962
	// THEME AUTHORS: Above this line is a great place to make customizations to the posting_fields array
963
964
	// Start printing the header
965
	echo '
966
					<dl id="post_header">';
967
968
	foreach ($context['posting_fields'] as $pfid => $pf)
969
	{
970
		// We need both a label and an input
971
		if (empty($pf['label']) || empty($pf['input']))
972
			continue;
973
974
		// The labels are pretty simple...
975
		echo '
976
						<dt class="clear pf_', $pfid, '">';
977
978
		// Any leading HTML before the label
979
		if (!empty($pf['label']['before']))
980
			echo '
981
							', $pf['label']['before'];
982
983
		if (!empty($pf['label']['html']))
984
			echo $pf['label']['html'];
985
		else
986
			echo '
987
							<label', ($pf['input']['type'] === 'radio_select' ? '' : ' for="' . (!empty($pf['input']['attributes']['id']) ? $pf['input']['attributes']['id'] : $pfid) . '"'), ' id="caption_', $pfid, '"', !empty($pf['label']['class']) ? ' class="' . $pf['label']['class'] . '"' : '', '>', $pf['label']['text'], '</label>';
988
989
		// Any trailing HTML after the label
990
		if (!empty($pf['label']['after']))
991
			echo '
992
							', $pf['label']['after'];
993
994
		echo '
995
						</dt>';
996
997
		// Here's where the fun begins...
998
		echo '
999
						<dd class="pf_', $pfid, '">';
1000
1001
		// Any leading HTML before the main input
1002
		if (!empty($pf['input']['before']))
1003
			echo '
1004
							', $pf['input']['before'];
1005
1006
		// If there is a literal HTML string already defined, just print it.
1007
		if (!empty($pf['input']['html']))
1008
		{
1009
			echo $pf['input']['html'];
1010
		}
1011
		// Simple text inputs and checkboxes
1012
		elseif (in_array($pf['input']['type'], array('text', 'password', 'color', 'date', 'datetime-local', 'email', 'month', 'number', 'range', 'tel', 'time', 'url', 'week', 'checkbox')))
1013
		{
1014
			echo '
1015
							<input type="', $pf['input']['type'], '"';
1016
1017
			if (empty($pf['input']['attributes']['id']))
1018
				echo ' id="', $pfid, '"';
1019
1020
			if (empty($pf['input']['attributes']['name']))
1021
				echo ' name="', $pfid, '"';
1022
1023
			if (!empty($pf['input']['attributes']) && is_array($pf['input']['attributes']))
1024
			{
1025
				foreach ($pf['input']['attributes'] as $attribute => $value)
1026
				{
1027
					if (is_bool($value))
1028
						echo $value ? ' ' . $attribute : '';
1029
					else
1030
						echo ' ', $attribute, '="', $value, '"';
1031
				}
1032
			}
1033
1034
			echo ' tabindex="', $context['tabindex']++, '">';
1035
		}
1036
		// textarea
1037
		elseif ($pf['input']['type'] === 'textarea')
1038
		{
1039
			echo '
1040
							<textarea';
1041
1042
			if (empty($pf['input']['attributes']['id']))
1043
				echo ' id="', $pfid, '"';
1044
1045
			if (empty($pf['input']['attributes']['name']))
1046
				echo ' name="', $pfid, '"';
1047
1048
			if (!empty($pf['input']['attributes']) && is_array($pf['input']['attributes']))
1049
			{
1050
				foreach ($pf['input']['attributes'] as $attribute => $value)
1051
				{
1052
					if ($attribute === 'value')
1053
						continue;
1054
					elseif (is_bool($value))
1055
						echo $value ? ' ' . $attribute : '';
1056
					else
1057
						echo ' ', $attribute, '="', $value, '"';
1058
				}
1059
			}
1060
1061
			echo ' tabindex="', $context['tabindex']++, '">', !empty($pf['input']['attributes']['value']) ? $pf['input']['attributes']['value'] : '', '</textarea>';
1062
		}
1063
		// Select menus are more complicated
1064
		elseif ($pf['input']['type'] === 'select' && is_array($pf['input']['options']))
1065
		{
1066
			// The select element itself
1067
			echo '
1068
							<select';
1069
1070
			if (empty($pf['input']['attributes']['id']))
1071
				echo ' id="', $pfid, '"';
1072
1073
			if (empty($pf['input']['attributes']['name']))
1074
				echo ' name="', $pfid, !empty($pf['input']['attributes']['multiple']) ? '[]' : '', '"';
1075
1076
			if (!empty($pf['input']['attributes']) && is_array($pf['input']['attributes']))
1077
			{
1078
				foreach ($pf['input']['attributes'] as $attribute => $value)
1079
				{
1080
					if (is_bool($value))
1081
						echo $value ? ' ' . $attribute : '';
1082
					else
1083
						echo ' ', $attribute, '="', $value, '"';
1084
				}
1085
			}
1086
1087
			echo ' tabindex="', $context['tabindex']++, '">';
1088
1089
			// The options
1090
			foreach ($pf['input']['options'] as $optlabel => $option)
1091
			{
1092
				// An option containing options is an optgroup
1093
				if (!empty($option['options']) && is_array($option['options']))
1094
				{
1095
					echo '
1096
								<optgroup';
1097
1098
					if (empty($option['label']))
1099
						echo ' label="', $optlabel, '"';
1100
1101
					if (!empty($option) && is_array($option))
1102
					{
1103
						foreach ($option as $attribute => $value)
1104
						{
1105
							if ($attribute === 'options')
1106
								continue;
1107
							elseif (is_bool($value))
1108
								echo $value ? ' ' . $attribute : '';
1109
							else
1110
								echo ' ', $attribute, '="', $value, '"';
1111
						}
1112
					}
1113
1114
					echo '>';
1115
1116
					foreach ($option['options'] as $grouped_optlabel => $grouped_option)
1117
					{
1118
						echo '
1119
									<option';
1120
1121
						foreach ($grouped_option as $attribute => $value)
1122
						{
1123
							if (is_bool($value))
1124
								echo $value ? ' ' . $attribute : '';
1125
							else
1126
								echo ' ', $attribute, '="', $value, '"';
1127
						}
1128
1129
						echo '>', $grouped_option['label'], '</option>';
1130
1131
					}
1132
1133
					echo '
1134
								</optgroup>';
1135
				}
1136
				// Simple option
1137
				else
1138
				{
1139
					echo '
1140
								<option';
1141
1142
					foreach ($option as $attribute => $value)
1143
					{
1144
						if (is_bool($value))
1145
							echo $value ? ' ' . $attribute : '';
1146
						else
1147
							echo ' ', $attribute, '="', $value, '"';
1148
					}
1149
1150
					echo '>', $optlabel, '</option>';
1151
				}
1152
			}
1153
1154
			// Close the select element
1155
			echo '
1156
							</select>';
1157
		}
1158
		// Radio_select makes a div with some radio buttons in it
1159
		elseif ($pf['input']['type'] === 'radio_select' && is_array($pf['input']['options']))
1160
		{
1161
			echo '
1162
							<div';
1163
1164
			if (!empty($pf['input']['attributes']) && is_array($pf['input']['attributes']))
1165
			{
1166
				foreach ($pf['input']['attributes'] as $attribute => $value)
1167
				{
1168
					if ($attribute === 'name')
1169
						continue;
1170
					elseif (is_bool($value))
1171
						echo $value ? ' ' . $attribute : '';
1172
					else
1173
						echo ' ', $attribute, '="', $value, '"';
1174
				}
1175
			}
1176
1177
			echo '>';
1178
1179
			foreach ($pf['input']['options'] as $optlabel => $option)
1180
			{
1181
				echo '
1182
							<label style="margin-right:2ch"><input type="radio" name="', !empty($pf['input']['attributes']['name']) ? $pf['input']['attributes']['name'] : $pfid, '"';
1183
1184
				foreach ($option as $attribute => $value)
1185
				{
1186
					if ($attribute === 'label')
1187
						continue;
1188
					elseif (is_bool($value))
1189
						echo $value ? ' ' . ($attribute === 'selected' ? 'checked' : $attribute) : '';
1190
					else
1191
						echo ' ', $attribute, '="', $value, '"';
1192
				}
1193
1194
				echo ' tabindex="', $context['tabindex']++, '"> ', isset($option['label']) ? $option['label'] : $optlabel, '</label>';
1195
			}
1196
1197
			echo '
1198
							</div>';
1199
		}
1200
1201
		// Any trailing HTML after the main input
1202
		if (!empty($pf['input']['after']))
1203
			echo '
1204
							', $pf['input']['after'];
1205
1206
		echo '
1207
						</dd>';
1208
	}
1209
1210
	echo '
1211
					</dl>';
1212
}
1213
1214
?>