Completed
Push — release-2.1 ( 89d81d...05ee2b )
by Jeremy
08:15
created

Themes.template.php ➔ template_edit_file()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 38

Duplication

Lines 3
Ratio 7.89 %

Importance

Changes 0
Metric Value
cc 5
nc 8
nop 0
dl 3
loc 38
rs 9.0008
c 0
b 0
f 0
1
<?php
2
/**
3
 * Simple Machines Forum (SMF)
4
 *
5
 * @package SMF
6
 * @author Simple Machines http://www.simplemachines.org
7
 * @copyright 2018 Simple Machines and individual contributors
8
 * @license http://www.simplemachines.org/about/smf/license.php BSD
9
 *
10
 * @version 2.1 Beta 4
11
 */
12
13
/**
14
 * The main sub template - for theme administration.
15
 */
16
function template_main()
0 ignored issues
show
Best Practice introduced by
The function template_main() has been defined more than once; this definition is ignored, only the first definition in Themes/default/BoardIndex.template.php (L54-132) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
17
{
18
	global $context, $scripturl, $txt, $modSettings;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
19
20
	// Theme install info.
21
	echo '
22
		<div class="cat_bar">
23
			<h3 class="catbg">
24
				<a href="', $scripturl, '?action=helpadmin;help=themes" onclick="return reqOverlayDiv(this.href);" class="help"><span class="generic_icons help" title="', $txt['help'], '"></span></a>
25
				', $txt['themeadmin_title'], '
26
			</h3>
27
		</div>
28
		<div class="information">
29
			', $txt['themeadmin_explain'], '
30
		</div>';
31
32
	echo '
33
		<form action="', $scripturl, '?action=admin;area=theme;sa=admin" method="post" accept-charset="', $context['character_set'], '">
34
			<div class="cat_bar">
35
				<h3 class="catbg">',
36
					$txt['settings'], '
37
				</h3>
38
			</div>
39
			<div class="windowbg">
40
				<dl class="settings">
41
					<dt>
42
						<label for="options-theme_allow"> ', $txt['theme_allow'], '</label>
43
					</dt>
44
					<dd>
45
						<input type="hidden" value="0" name="options[theme_allow]">
46
						<input type="checkbox" name="options[theme_allow]" id="options-theme_allow" value="1"', !empty($modSettings['theme_allow']) ? ' checked' : '', '>
47
					</dd>
48
					<dt>
49
						<label for="known_themes_list">', $txt['themeadmin_selectable'], '</label>:
50
					</dt>
51
					<dd>
52
						<div id="known_themes_list">';
53
54 View Code Duplication
	foreach ($context['themes'] as $theme)
55
		echo '
56
							<label for="options-known_themes_', $theme['id'], '"><input type="checkbox" name="options[known_themes][]" id="options-known_themes_', $theme['id'], '" value="', $theme['id'], '"', $theme['known'] ? ' checked' : '', '> ', $theme['name'], '</label><br>';
57
58
	echo '
59
						</div>
60
						<a href="javascript:void(0);" onclick="document.getElementById(\'known_themes_list\').style.display=\'block\'; document.getElementById(\'known_themes_link\').style.display = \'none\'; return false; " id="known_themes_link" style="display: none;">[ ', $txt['themeadmin_themelist_link'], ' ]</a>
61
						<script>
62
							document.getElementById("known_themes_list").style.display = "none";
63
							document.getElementById("known_themes_link").style.display = "";
64
						</script>
65
					</dd>
66
					<dt>
67
						<label for="theme_guests">', $txt['theme_guests'], ':</label>
68
					</dt>
69
					<dd>
70
						<select name="options[theme_guests]" id="theme_guests">';
71
72
	// Put an option for each theme in the select box.
73 View Code Duplication
	foreach ($context['themes'] as $theme)
74
		echo '
75
							<option value="', $theme['id'], '"', $modSettings['theme_guests'] == $theme['id'] ? ' selected' : '', '>', $theme['name'], '</option>';
76
77
	echo '
78
						</select>
79
						<span class="smalltext pick_theme"><a href="', $scripturl, '?action=theme;sa=pick;u=-1;', $context['session_var'], '=', $context['session_id'], '">', $txt['theme_select'], '</a></span>
80
					</dd>
81
					<dt>
82
						<label for="theme_reset">', $txt['theme_reset'], '</label>:
83
					</dt>
84
					<dd>
85
						<select name="theme_reset" id="theme_reset">
86
							<option value="-1" selected>', $txt['theme_nochange'], '</option>
87
							<option value="0">', $txt['theme_forum_default'], '</option>';
88
89
	// Same thing, this time for changing the theme of everyone.
90
	foreach ($context['themes'] as $theme)
91
		echo '
92
							<option value="', $theme['id'], '">', $theme['name'], '</option>';
93
94
	echo '
95
						</select>
96
						<span class="smalltext pick_theme"><a href="', $scripturl, '?action=theme;sa=pick;u=0;', $context['session_var'], '=', $context['session_id'], '">', $txt['theme_select'], '</a></span>
97
					</dd>
98
				</dl>
99
				<input type="submit" name="save" value="' . $txt['save'] . '" class="button">
100
				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
101
				<input type="hidden" name="', $context['admin-tm_token_var'], '" value="', $context['admin-tm_token'], '">
102
			</div><!-- .windowbg -->
103
		</form>';
104
105
	// Link to simplemachines.org for latest themes and info!
106
	echo '
107
		<div class="cat_bar">
108
			<h3 class="catbg">
109
				', $txt['theme_adding_title'], '
110
			</h3>
111
		</div>
112
		<div class="windowbg">
113
			', $txt['theme_adding'], '
114
		</div>';
115
116
	// All the install options.
117
	echo '
118
		<div id="admin_form_wrapper">
119
			<div class="cat_bar">
120
				<h3 class="catbg">
121
					', $txt['theme_install'], '
122
				</h3>
123
			</div>
124
			<div class="windowbg">';
125
126
	if ($context['can_create_new'])
127
	{
128
		// From a file.
129
		echo '
130
				<fieldset>
131
					<legend>', $txt['theme_install_file'], '</legend>
132
					<form action="', $scripturl, '?action=admin;area=theme;sa=install;do=file" method="post" accept-charset="', $context['character_set'], '" enctype="multipart/form-data" class="padding">
133
						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
134
						<input type="hidden" name="', $context['admin-t-file_token_var'], '" value="', $context['admin-t-file_token'], '">
135
						<input type="file" name="theme_gz" id="theme_gz" value="theme_gz" size="40" onchange="this.form.copy.disabled = this.value != \'\'; this.form.theme_dir.disabled = this.value != \'\';">
136
						<input type="submit" name="save_file" value="' . $txt['upload'] . '" class="button">
137
					</form>
138
				</fieldset>';
139
140
		// Copied from the default.
141
		echo '
142
				<fieldset>
143
					<legend>', $txt['theme_install_new'], '</legend>
144
					<form action="', $scripturl, '?action=admin;area=theme;sa=install;do=copy" method="post" accept-charset="', $context['character_set'], '" class="padding">
145
						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
146
						<input type="hidden" name="', $context['admin-t-copy_token_var'], '" value="', $context['admin-t-copy_token'], '">
147
						<input type="text" name="copy" id="copy" value="', $context['new_theme_name'], '" size="40">
148
						<input type="submit" name="save_copy" value="' . $txt['save'] . '" class="button">
149
					</form>
150
				</fieldset>';
151
	}
152
153
	// From a dir.
154
	echo '
155
				<fieldset>
156
					<legend>', $txt['theme_install_dir'], '</legend>
157
					<form action="', $scripturl, '?action=admin;area=theme;sa=install;do=dir" method="post" accept-charset="', $context['character_set'], '" class="padding">
158
						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
159
						<input type="hidden" name="', $context['admin-t-dir_token_var'], '" value="', $context['admin-t-dir_token'], '">
160
						<input type="text" name="theme_dir" id="theme_dir" value="', $context['new_theme_dir'], '" size="40">
161
						<input type="submit" name="save_dir" value="' . $txt['save'] . '" class="button">
162
					</form>
163
				</fieldset>';
164
165
	echo '
166
			</div><!-- .windowbg -->
167
		</div><!-- #admin_form_wrapper -->';
168
169
	echo '
170
	<script>
171
		window.smfForum_scripturl = smf_scripturl;
172
		window.smfForum_sessionid = smf_session_id;
173
		window.smfForum_sessionvar = smf_session_var;
174
		window.smfThemes_writable = ', $context['can_create_new'] ? 'true' : 'false', ';
175
	</script>';
176
}
177
178
/**
179
 * This lists all themes
180
 */
181
function template_list_themes()
182
{
183
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
184
185
	// Show a nice confirmation message.
186
	if (isset($_GET['done']))
187
		echo '
188
	<div class="infobox">
189
		', $txt['theme_confirmed_' . $_GET['done']], '
190
	</div>';
191
192
	echo '
193
		<div class="cat_bar">
194
			<h3 class="catbg">', $txt['themeadmin_list_heading'], '</h3>
195
		</div>
196
		<div class="information">
197
			', $txt['themeadmin_list_tip'], '
198
		</div>
199
		<form id="admin_form_wrapper" action="', $scripturl, '?action=admin;area=theme;', $context['session_var'], '=', $context['session_id'], ';sa=list" method="post" accept-charset="', $context['character_set'], '">
200
			<div class="cat_bar">
201
				<h3 class="catbg">', $txt['theme_settings'], '</h3>
202
			</div>
203
			<br>';
204
205
	// Show each theme.... with X for delete, an enable/disable link and a link to their own settings page.
206
	foreach ($context['themes'] as $theme)
207
	{
208
		echo '
209
			<div class="cat_bar">
210
				<h3 class="catbg">
211
					<span class="floatleft">
212
						', (!empty($theme['enable']) || $theme['id'] == 1 ? '<a href="' . $scripturl . '?action=admin;area=theme;th=' . $theme['id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=list">' . $theme['name'] . '</a>' : $theme['name']), '', (!empty($theme['version']) ? ' <em>(' . $theme['version'] . ')</em>' : ''), '
213
					</span>';
214
215
		// You *cannot* disable/enable/delete the default theme. It's important!
216
		if ($theme['id'] != 1)
217
		{
218
			echo '
219
					<span class="floatright">';
220
221
			// Enable/Disable.
222
			echo '
223
						<a href="', $scripturl, '?action=admin;area=theme;sa=enable;th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], ';', $context['admin-tre_token_var'], '=', $context['admin-tre_token'], '', (!empty($theme['enable']) ? ';disabled' : ''), '" data-confirm="', $txt['theme_' . (!empty($theme['enable']) ? 'disable' : 'enable') . '_confirm'], '" class="you_sure"><span class="generic_icons ', !empty($theme['enable']) ? 'disable' : 'enable', '" title="', $txt['theme_' . (!empty($theme['enable']) ? 'disable' : 'enable')], '"></span></a>';
224
225
			// Deleting.
226
			echo '
227
						<a href="', $scripturl, '?action=admin;area=theme;sa=remove;th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], ';', $context['admin-tr_token_var'], '=', $context['admin-tr_token'], '" data-confirm="', $txt['theme_remove_confirm'], '" class="you_sure"><span class="generic_icons delete" title="', $txt['theme_remove'], '"></span></a>';
228
229
			echo '
230
					</span>';
231
		}
232
233
		echo '
234
				</h3>
235
			</div><!-- .cat_bar -->
236
			<div class="windowbg">
237
				<dl class="settings themes_list">
238
					<dt>', $txt['themeadmin_list_theme_dir'], ':</dt>
239
					<dd', $theme['valid_path'] ? '' : ' class="error"', '>', $theme['theme_dir'], $theme['valid_path'] ? '' : ' ' . $txt['themeadmin_list_invalid'], '</dd>
240
					<dt>', $txt['themeadmin_list_theme_url'], ':</dt>
241
					<dd>', $theme['theme_url'], '</dd>
242
					<dt>', $txt['themeadmin_list_images_url'], ':</dt>
243
					<dd>', $theme['images_url'], '</dd>
244
				</dl>
245
			</div>';
246
	}
247
248
	echo '
249
			<div class="cat_bar">
250
				<h3 class="catbg">', $txt['themeadmin_list_reset'], '</h3>
251
			</div>
252
			<div class="windowbg">
253
				<dl class="settings">
254
					<dt>
255
						<label for="reset_dir">', $txt['themeadmin_list_reset_dir'], '</label>:
256
					</dt>
257
					<dd>
258
						<input type="text" name="reset_dir" id="reset_dir" value="', $context['reset_dir'], '" size="40">
259
					</dd>
260
					<dt>
261
						<label for="reset_url">', $txt['themeadmin_list_reset_url'], '</label>:
262
					</dt>
263
					<dd>
264
						<input type="text" name="reset_url" id="reset_url" value="', $context['reset_url'], '" size="40">
265
					</dd>
266
				</dl>
267
				<input type="submit" name="save" value="', $txt['themeadmin_list_reset_go'], '" class="button">
268
				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
269
				<input type="hidden" name="', $context['admin-tl_token_var'], '" value="', $context['admin-tl_token'], '">
270
			</div>
271
		</form>';
272
}
273
274
/**
275
 * This lets you reset themes
276
 */
277
function template_reset_list()
278
{
279
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
280
281
	echo '
282
		<div class="cat_bar">
283
			<h3 class="catbg">', $txt['themeadmin_reset_title'], '</h3>
284
		</div>
285
		<div class="information">
286
			', $txt['themeadmin_reset_tip'], '
287
		</div>
288
		<div id="admin_form_wrapper">';
289
290
	// Show each theme.... with X for delete and a link to settings.
291
	foreach ($context['themes'] as $theme)
292
	{
293
		echo '
294
			<div class="cat_bar">
295
				<h3 class="catbg">', $theme['name'], '</h3>
296
			</div>
297
			<div class="windowbg">
298
				<ul>
299
					<li>
300
						<a href="', $scripturl, '?action=admin;area=theme;th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=reset">', $txt['themeadmin_reset_defaults'], '</a> <em class="smalltext">(', $theme['num_default_options'], ' ', $txt['themeadmin_reset_defaults_current'], ')</em>
301
					</li>
302
					<li>
303
						<a href="', $scripturl, '?action=admin;area=theme;th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=reset;who=1">', $txt['themeadmin_reset_members'], '</a>
304
					</li>
305
					<li>
306
						<a href="', $scripturl, '?action=admin;area=theme;th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=reset;who=2;', $context['admin-stor_token_var'], '=', $context['admin-stor_token'], '" data-confirm="', $txt['themeadmin_reset_remove_confirm'], '" class="you_sure">', $txt['themeadmin_reset_remove'], '</a> <em class="smalltext">(', $theme['num_members'], ' ', $txt['themeadmin_reset_remove_current'], ')</em>
307
					</li>
308
				</ul>
309
			</div>';
310
	}
311
312
	echo '
313
		</div><!-- #admin_form_wrapper -->';
314
}
315
316
/**
317
 * This displays the form for setting theme options
318
 */
319
function template_set_options()
320
{
321
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
322
323
	echo '
324
		<form action="', $scripturl, '?action=admin;area=theme;th=', $context['theme_settings']['theme_id'], ';sa=reset" method="post" accept-charset="', $context['character_set'], '">
325
			<input type="hidden" name="who" value="', $context['theme_options_reset'] ? 1 : 0, '">
326
			<div class="cat_bar">
327
				<h3 class="catbg">
328
					', $txt['theme_options_title'], ' - ', $context['theme_settings']['name'], '
329
				</h3>
330
			</div>
331
			<div class="information noup">
332
				', $context['theme_options_reset'] ? $txt['themeadmin_reset_options_info'] : $txt['theme_options_defaults'], '
333
			</div>
334
			<div class="windowbg noup">
335
				<dl class="settings">';
336
337
	$skeys = array_keys($context['options']);
338
	$first_option_key = array_shift($skeys);
339
	$titled_section = false;
340
341
	foreach ($context['options'] as $i => $setting)
342
	{
343
		// Just spit out separators and move on
344 View Code Duplication
		if (empty($setting) || !is_array($setting))
345
		{
346
			// Insert a separator (unless this is the first item in the list)
347
			if ($i !== $first_option_key)
348
				echo '
349
				</dl>
350
				<hr>
351
				<dl class="settings">';
352
353
			// Should we give a name to this section?
354
			if (is_string($setting) && !empty($setting))
355
			{
356
				$titled_section = true;
357
				echo '
358
					<dt><strong>' . $setting . '</strong></dt>
359
					<dd></dd>';
360
			}
361
			else
362
				$titled_section = false;
363
364
			continue;
365
		}
366
367
		echo '
368
					<dt>';
369
370
		// Show the change option box?
371
		if ($context['theme_options_reset'])
372
			echo '
373
						<span class="floatleft">
374
							<select name="', !empty($setting['default']) ? 'default_' : '', 'options_master[', $setting['id'], ']" onchange="this.form.options_', $setting['id'], '.disabled = this.selectedIndex != 1;">
375
								<option value="0" selected>', $txt['themeadmin_reset_options_none'], '</option>
376
								<option value="1">', $txt['themeadmin_reset_options_change'], '</option>
377
								<option value="2">', $txt['themeadmin_reset_options_default'], '</option>
378
							</select>
379
						</span>';
380
381
		echo '
382
						<label for="options_', $setting['id'], '">', !$titled_section ? '<strong>' : '', $setting['label'], !$titled_section ? '</strong>' : '', '</label>';
383
384
		if (isset($setting['description']))
385
			echo '
386
						<br>
387
						<span class="smalltext">', $setting['description'], '</span>';
388
		echo '
389
					</dt>';
390
391
		// Display checkbox options
392
		if ($setting['type'] == 'checkbox')
393
			echo '
394
					<dd>
395
						<input type="hidden" name="' . (!empty($setting['default']) ? 'default_' : '') . 'options[' . $setting['id'] . ']" value="0">
396
						<input type="checkbox" name="', !empty($setting['default']) ? 'default_' : '', 'options[', $setting['id'], ']" id="options_', $setting['id'], '"', !empty($setting['value']) ? ' checked' : '', $context['theme_options_reset'] ? ' disabled' : '', ' value="1" class="floatleft">';
397
398
		// How about selection lists, we all love them
399
		elseif ($setting['type'] == 'list')
400
		{
401
			echo '
402
					<dd>
403
						<select class="floatleft" name="', !empty($setting['default']) ? 'default_' : '', 'options[', $setting['id'], ']" id="options_', $setting['id'], '"', $context['theme_options_reset'] ? ' disabled' : '', '>';
404
405
			foreach ($setting['options'] as $value => $label)
406
				echo '
407
							<option value="', $value, '"', $value == $setting['value'] ? ' selected' : '', '>', $label, '</option>';
408
409
			echo '
410
						</select>';
411
		}
412
		// A textbox it is then
413 View Code Duplication
		else
414
		{
415
			echo '
416
					<dd>';
417
418
			if (isset($setting['type']) && $setting['type'] == 'number')
419
			{
420
				$min = isset($setting['min']) ? ' min="' . $setting['min'] . '"' : ' min="0"';
421
				$max = isset($setting['max']) ? ' max="' . $setting['max'] . '"' : '';
422
				$step = isset($setting['step']) ? ' step="' . $setting['step'] . '"' : '';
423
424
				echo '
425
						<input type="number"', $min . $max . $step;
426
			}
427
			elseif (isset($setting['type']) && $setting['type'] == 'url')
428
				echo'
429
						<input type="url"';
430
431
			else
432
				echo '
433
						<input type="text"';
434
435
			echo ' name="', !empty($setting['default']) ? 'default_' : '', 'options[', $setting['id'], ']" id="options_', $setting['id'], '" value="', $setting['value'], '"', $setting['type'] == 'number' ? ' size="5"' : '', $context['theme_options_reset'] ? ' disabled' : '', '>';
436
		}
437
438
		// End of this defintion, close open dds
439
		echo '
440
					</dd>';
441
	}
442
443
	// Close the option page up
444
	echo '
445
				</dl>
446
				<input type="submit" name="submit" value="', $txt['save'], '" class="button">
447
				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
448
				<input type="hidden" name="', $context['admin-sto_token_var'], '" value="', $context['admin-sto_token'], '">
449
			</div>
450
		</form>';
451
}
452
453
/**
454
 * The page for setting and managing theme settings.
455
 */
456
function template_set_settings()
457
{
458
	global $context, $settings, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
459
460
	echo '
461
	<div id="admin_form_wrapper">
462
		<form action="', $scripturl, '?action=admin;area=theme;sa=list;th=', $context['theme_settings']['theme_id'], '" method="post" accept-charset="', $context['character_set'], '">
463
			<div class="cat_bar">
464
				<h3 class="catbg">
465
					<a href="', $scripturl, '?action=helpadmin;help=theme_settings" onclick="return reqOverlayDiv(this.href);" class="help"><span class="generic_icons help" title="', $txt['help'], '"></span></a> ', $txt['theme_settings'], ' - ', $context['theme_settings']['name'], '
466
				</h3>
467
			</div>
468
			<div class="windowbg">';
469
470
	// @todo Why can't I edit the default theme popup.
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
471
	if ($context['theme_settings']['theme_id'] != 1)
472
		echo '
473
				<div class="title_bar">
474
					<h3 class="titlebg config_hd">
475
						', $txt['theme_edit'], '
476
					</h3>
477
				</div>
478
				<div class="windowbg">
479
					<ul>
480
						<li>
481
							<a href="', $scripturl, '?action=admin;area=theme;th=', $context['theme_settings']['theme_id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=edit;filename=index.template.php">', $txt['theme_edit_index'], '</a>
482
						</li>
483
						<li>
484
							<a href="', $scripturl, '?action=admin;area=theme;th=', $context['theme_settings']['theme_id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=edit;directory=css">', $txt['theme_edit_style'], '</a>
485
						</li>
486
					</ul>
487
				</div>';
488
489
	echo '
490
				<div class="title_bar">
491
					<h3 class="titlebg config_hd">
492
						', $txt['theme_url_config'], '
493
					</h3>
494
				</div>
495
				<dl class="settings">
496
					<dt>
497
						<label for="theme_name">', $txt['actual_theme_name'], '</label>
498
					</dt>
499
					<dd>
500
						<input type="text" id="theme_name" name="options[name]" value="', $context['theme_settings']['name'], '" size="32">
501
					</dd>
502
					<dt>
503
						<label for="theme_url">', $txt['actual_theme_url'], '</label>
504
					</dt>
505
					<dd>
506
						<input type="text" id="theme_url" name="options[theme_url]" value="', $context['theme_settings']['actual_theme_url'], '" size="50">
507
					</dd>
508
					<dt>
509
						<label for="images_url">', $txt['actual_images_url'], '</label>
510
					</dt>
511
					<dd>
512
						<input type="text" id="images_url" name="options[images_url]" value="', $context['theme_settings']['actual_images_url'], '" size="50">
513
					</dd>
514
					<dt>
515
						<label for="theme_dir">', $txt['actual_theme_dir'], '</label>
516
					</dt>
517
					<dd>
518
						<input type="text" id="theme_dir" name="options[theme_dir]" value="', $context['theme_settings']['actual_theme_dir'], '" size="50">
519
					</dd>
520
				</dl>';
521
522
	// Do we allow theme variants?
523
	if (!empty($context['theme_variants']))
524
	{
525
		echo '
526
				<div class="title_bar">
527
					<h3 class="titlebg config_hd">
528
						', $txt['theme_variants'], '
529
					</h3>
530
				</div>
531
				<dl class="settings">
532
					<dt>
533
						<label for="variant">', $txt['theme_variants_default'], '</label>:
534
					</dt>
535
					<dd>
536
						<select id="variant" name="options[default_variant]" onchange="changeVariant(this.value)">';
537
538 View Code Duplication
		foreach ($context['theme_variants'] as $key => $variant)
539
			echo '
540
							<option value="', $key, '"', $context['default_variant'] == $key ? ' selected' : '', '>', $variant['label'], '</option>';
541
542
		echo '
543
						</select>
544
					</dd>
545
					<dt>
546
						<label for="disable_user_variant">', $txt['theme_variants_user_disable'], '</label>:
547
					</dt>
548
					<dd>
549
						<input type="hidden" name="options[disable_user_variant]" value="0">
550
						<input type="checkbox" name="options[disable_user_variant]" id="disable_user_variant"', !empty($context['theme_settings']['disable_user_variant']) ? ' checked' : '', ' value="1">
551
					</dd>
552
				</dl>
553
				<img src="', $context['theme_variants'][$context['default_variant']]['thumbnail'], '" id="variant_preview" alt="">';
554
	}
555
556
	echo '
557
				<div class="title_bar">
558
					<h3 class="titlebg config_hd">
559
						', $txt['theme_options'], '
560
					</h3>
561
				</div>
562
				<dl class="settings">';
563
564
	$skeys = array_keys($context['settings']);
565
	$first_setting_key = array_shift($skeys);
566
	$titled_section = false;
567
568
	foreach ($context['settings'] as $i => $setting)
569
	{
570
		// Is this a separator?
571 View Code Duplication
		if (empty($setting) || !is_array($setting))
572
		{
573
			// We don't need a separator before the first list element
574
			if ($i !== $first_setting_key)
575
				echo '
576
				</dl>
577
				<hr>
578
				<dl class="settings">';
579
580
			// Add a fake heading?
581
			if (is_string($setting) && !empty($setting))
582
			{
583
				$titled_section = true;
584
				echo '
585
					<dt><strong>' . $setting . '</strong></dt>
586
					<dd></dd>';
587
			}
588
			else
589
				$titled_section = false;
590
591
			continue;
592
		}
593
594
		echo '
595
					<dt>
596
						<label for="', $setting['id'], '">', !$titled_section ? '<strong>' : '', $setting['label'], !$titled_section ? '</strong>' : '', '</label>:';
597
598
		if (isset($setting['description']))
599
			echo '<br>
600
						<span class="smalltext">', $setting['description'], '</span>';
601
602
		echo '
603
					</dt>';
604
605
		// A checkbox?
606
		if ($setting['type'] == 'checkbox')
607
			echo '
608
					<dd>
609
						<input type="hidden" name="', !empty($setting['default']) ? 'default_' : '', 'options[', $setting['id'], ']" value="0">
610
						<input type="checkbox" name="', !empty($setting['default']) ? 'default_' : '', 'options[', $setting['id'], ']" id="', $setting['id'], '"', !empty($setting['value']) ? ' checked' : '', ' value="1">
611
					</dd>';
612
613
		// A list with options?
614 View Code Duplication
		elseif ($setting['type'] == 'list')
615
		{
616
			echo '
617
					<dd>
618
						<select name="', !empty($setting['default']) ? 'default_' : '', 'options[', $setting['id'], ']" id="', $setting['id'], '">';
619
620
			foreach ($setting['options'] as $value => $label)
621
				echo '
622
							<option value="', $value, '"', $value == $setting['value'] ? ' selected' : '', '>', $label, '</option>';
623
624
			echo '
625
						</select>
626
					</dd>';
627
		}
628
		// A Textarea?
629
		elseif ($setting['type'] == 'textarea')
630
		{
631
			echo '
632
					<dd>
633
						<textarea rows="4" style="width: 95%;" cols="40" name="', !empty($setting['default']) ? 'default_' : '', 'options[', $setting['id'], ']" id="', $setting['id'], '">', $setting['value'], '</textarea>
634
					</dd>';
635
		}
636
		// A regular input box, then?
637 View Code Duplication
		else
638
		{
639
			echo '
640
					<dd>';
641
642
			if (isset($setting['type']) && $setting['type'] == 'number')
643
			{
644
				$min = isset($setting['min']) ? ' min="' . $setting['min'] . '"' : ' min="0"';
645
				$max = isset($setting['max']) ? ' max="' . $setting['max'] . '"' : '';
646
				$step = isset($setting['step']) ? ' step="' . $setting['step'] . '"' : '';
647
648
				echo '
649
						<input type="number"', $min . $max . $step;
650
			}
651
			elseif (isset($setting['type']) && $setting['type'] == 'url')
652
				echo'
653
						<input type="url"';
654
655
			else
656
				echo '
657
						<input type="text"';
658
659
			echo ' name="', !empty($setting['default']) ? 'default_' : '', 'options[', $setting['id'], ']" id="options_', $setting['id'], '" value="', $setting['value'], '"', $setting['type'] == 'number' ? ' size="5"' : (empty($settings['size']) ? ' size="40"' : ' size="' . $setting['size'] . '"'), '>
660
					</dd>';
661
		}
662
	}
663
664
	echo '
665
				</dl>
666
				<input type="submit" name="save" value="', $txt['save'], '" class="button">
667
				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">
668
				<input type="hidden" name="', $context['admin-sts_token_var'], '" value="', $context['admin-sts_token'], '">
669
			</div><!-- .windowbg -->
670
		</form>
671
	</div><!-- #admin_form_wrapper -->';
672
673
	if (!empty($context['theme_variants']))
674
	{
675
		echo '
676
		<script>
677
		var oThumbnails = {';
678
679
		// All the variant thumbnails.
680
		$count = 1;
681 View Code Duplication
		foreach ($context['theme_variants'] as $key => $variant)
682
		{
683
			echo '
684
			\'', $key, '\': \'', $variant['thumbnail'], '\'', (count($context['theme_variants']) == $count ? '' : ',');
685
			$count++;
686
		}
687
688
		echo '
689
		}
690
		</script>';
691
	}
692
}
693
694
/**
695
 * This template allows for the selection of different themes ;)
696
 */
697
function template_pick()
698
{
699
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
700
701
	echo '
702
	<div id="pick_theme">
703
		<form action="', $scripturl, '?action=theme;sa=pick;u=', $context['current_member'], ';', $context['session_var'], '=', $context['session_id'], '" method="post" accept-charset="', $context['character_set'], '">';
704
705
	// Just go through each theme and show its information - thumbnail, etc.
706
	foreach ($context['available_themes'] as $theme)
707
	{
708
		echo '
709
			<div class="cat_bar">
710
				<h3 class="catbg">
711
					<a href="', $scripturl, '?action=theme;sa=pick;u=', $context['current_member'], ';th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], !empty($theme['variants']) ? ';vrt=' . $theme['selected_variant'] : '', '">', $theme['name'], '</a>
712
				</h3>
713
			</div>
714
			<div class="windowbg', $theme['selected'] ? ' selected' : '', '">
715
				<div class="flow_hidden">
716
					<div class="floatright">
717
						<a href="', $scripturl, '?action=theme;sa=pick;u=', $context['current_member'], ';theme=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], '" id="theme_thumb_preview_', $theme['id'], '" title="', $txt['theme_preview'], '">
718
							<img src="', $theme['thumbnail_href'], '" id="theme_thumb_', $theme['id'], '" alt="" class="padding">
719
						</a>
720
					</div>
721
					<p>', $theme['description'], '</p>';
722
723
		if (!empty($theme['variants']))
724
		{
725
			echo '
726
					<label for="variant', $theme['id'], '"><strong>', $theme['pick_label'], '</strong></label>:
727
					<select id="variant', $theme['id'], '" name="vrt[', $theme['id'], ']" onchange="changeVariant', $theme['id'], '(this.value);">';
728
729 View Code Duplication
			foreach ($theme['variants'] as $key => $variant)
730
				echo '
731
						<option value="', $key, '"', $theme['selected_variant'] == $key ? ' selected' : '', '>', $variant['label'], '</option>';
732
733
			echo '
734
					</select>
735
					<noscript>
736
						<input type="submit" name="save[', $theme['id'], ']" value="', $txt['save'], '" class="button">
737
					</noscript>';
738
		}
739
740
		echo '
741
					<br>
742
					<p>
743
						<em class="smalltext">', $theme['num_users'], ' ', ($theme['num_users'] == 1 ? $txt['theme_user'] : $txt['theme_users']), '</em>
744
					</p>
745
					<br>
746
					<ul>
747
						<li>
748
							<a href="', $scripturl, '?action=theme;sa=pick;u=', $context['current_member'], ';th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], !empty($theme['variants']) ? ';vrt=' . $theme['selected_variant'] : '', '" id="theme_use_', $theme['id'], '">[', $txt['theme_set'], ']</a>
749
						</li>
750
						<li>
751
							<a href="', $scripturl, '?action=theme;sa=pick;u=', $context['current_member'], ';theme=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], '" id="theme_preview_', $theme['id'], '">[', $txt['theme_preview'], ']</a>
752
						</li>
753
					</ul>
754
				</div>
755
			</div>';
756
757
		if (!empty($theme['variants']))
758
		{
759
			echo '
760
			<script>
761
			var sBaseUseUrl', $theme['id'], ' = smf_prepareScriptUrl(smf_scripturl) + \'action=theme;sa=pick;u=', $context['current_member'], ';th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], '\';
762
			var sBasePreviewUrl', $theme['id'], ' = smf_prepareScriptUrl(smf_scripturl) + \'action=theme;sa=pick;u=', $context['current_member'], ';theme=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], '\';
763
			var oThumbnails', $theme['id'], ' = {';
764
765
			// All the variant thumbnails.
766
			$count = 1;
767 View Code Duplication
			foreach ($theme['variants'] as $key => $variant)
768
			{
769
				echo '
770
				\'', $key, '\': \'', $variant['thumbnail'], '\'', (count($theme['variants']) == $count ? '' : ',');
771
				$count++;
772
			}
773
774
			echo '
775
			}
776
777
			function changeVariant', $theme['id'], '(sVariant)
778
			{
779
				document.getElementById(\'theme_thumb_', $theme['id'], '\').src = oThumbnails', $theme['id'], '[sVariant];
780
				document.getElementById(\'theme_use_', $theme['id'], '\').href = sBaseUseUrl', $theme['id'] == 0 ? $context['default_theme_id'] : $theme['id'], ' + \';vrt=\' + sVariant;
781
				document.getElementById(\'theme_thumb_preview_', $theme['id'], '\').href = sBasePreviewUrl', $theme['id'], ' + \';vrt=\' + sVariant + \';variant=\' + sVariant;
782
				document.getElementById(\'theme_preview_', $theme['id'], '\').href = sBasePreviewUrl', $theme['id'], ' + \';vrt=\' + sVariant + \';variant=\' + sVariant;
783
			}
784
			</script>';
785
		}
786
	}
787
788
	echo '
789
		</form>
790
	</div><!-- #pick_theme -->';
791
}
792
793
/**
794
 * Okay, that theme was installed/updated successfully!
795
 */
796
function template_installed()
797
{
798
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
799
800
	// The aftermath.
801
	echo '
802
		<div class="cat_bar">
803
			<h3 class="catbg">', $context['page_title'], '</h3>
804
		</div>
805
		<div class="windowbg">';
806
807
	// Oops! there was an error :(
808
	if (!empty($context['error_message']))
809
		echo '
810
			<p>
811
				', $context['error_message'], '
812
			</p>';
813
814
	// Not much to show except a link back...
815
	else
816
		echo '
817
			<p>
818
				<a href="', $scripturl, '?action=admin;area=theme;sa=list;th=', $context['installed_theme']['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $context['installed_theme']['name'], '</a> ', $txt['theme_' . (isset($context['installed_theme']['updated']) ? 'updated' : 'installed') . '_message'], '
819
			</p>
820
			<p>
821
				<a href="', $scripturl, '?action=admin;area=theme;sa=admin;', $context['session_var'], '=', $context['session_id'], '">', $txt['back'], '</a>
822
			</p>';
823
824
	echo '
825
		</div><!-- .windowbg -->';
826
}
827
828
/**
829
 * The page for editing themes.
830
 */
831
function template_edit_list()
832
{
833
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
834
835
	echo '
836
	<div id="admin_form_wrapper">
837
		<div class="cat_bar">
838
			<h3 class="catbg">', $txt['themeadmin_edit_title'], '</h3>
839
		</div>
840
		<div class="windowbg">';
841
842
	foreach ($context['themes'] as $theme)
843
	{
844
		echo '
845
			<fieldset>
846
				<legend>
847
					<a href="', $scripturl, '?action=admin;area=theme;th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=edit">', $theme['name'], '</a>', !empty($theme['version']) ? '
848
					<em>(' . $theme['version'] . ')</em>' : '', '
849
				</legend>
850
				<ul>
851
					<li><a href="', $scripturl, '?action=admin;area=theme;th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=edit">', $txt['themeadmin_edit_browse'], '</a></li>', $theme['can_edit_style'] ? '
852
					<li><a href="' . $scripturl . '?action=admin;area=theme;th=' . $theme['id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;directory=css">' . $txt['themeadmin_edit_style'] . '</a></li>' : '', '
853
					<li><a href="', $scripturl, '?action=admin;area=theme;th=', $theme['id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=copy">', $txt['themeadmin_edit_copy_template'], '</a></li>
854
				</ul>
855
			</fieldset>';
856
	}
857
858
	echo '
859
		</div><!-- .windowbg -->
860
	</div><!-- #admin_form_wrapper -->';
861
}
862
863
/**
864
 * The page allowing you to copy a template from one theme to another.
865
 */
866
function template_copy_template()
867
{
868
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
869
870
	echo '
871
		<div class="cat_bar">
872
			<h3 class="catbg">', $txt['themeadmin_edit_filename'], '</h3>
873
		</div>
874
		<div class="information">
875
			', $txt['themeadmin_edit_copy_warning'], '
876
		</div>
877
		<div class="windowbg">
878
			<ul class="theme_options">';
879
880
	foreach ($context['available_templates'] as $template)
881
	{
882
		echo '
883
				<li class="flow_hidden windowbg">
884
					<span class="floatleft">', $template['filename'], $template['already_exists'] ? ' <span class="error">(' . $txt['themeadmin_edit_exists'] . ')</span>' : '', '</span>
885
					<span class="floatright">';
886
887
		if ($template['can_copy'])
888
			echo '
889
						<a href="', $scripturl, '?action=admin;area=theme;th=', $context['theme_id'], ';', $context['session_var'], '=', $context['session_id'], ';sa=copy;template=', $template['value'], '" data-confirm="', $template['already_exists'] ? $txt['themeadmin_edit_overwrite_confirm'] : $txt['themeadmin_edit_copy_confirm'], '" class="you_sure">', $txt['themeadmin_edit_do_copy'], '</a>';
890
		else
891
			echo $txt['themeadmin_edit_no_copy'];
892
893
		echo '
894
					</span>
895
				</li>';
896
	}
897
898
	echo '
899
			</ul>
900
		</div><!-- .windowbg -->';
901
}
902
903
/**
904
 * This lets you browse a list of files in a theme so you can choose which one to edit.
905
 */
906
function template_edit_browse()
907
{
908
	global $context, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
909
910
	if (!empty($context['browse_title']))
911
		echo '
912
		<div class="cat_bar">
913
			<h3 class="catbg">', $context['browse_title'], '</h3>
914
		</div>';
915
916
	echo '
917
		<table class="table_grid tborder">
918
			<thead>
919
				<tr class="title_bar">
920
					<th class="lefttext half_table" scope="col">', $txt['themeadmin_edit_filename'], '</th>
921
					<th class="quarter_table" scope="col">', $txt['themeadmin_edit_modified'], '</th>
922
					<th class="quarter_table" scope="col">', $txt['themeadmin_edit_size'], '</th>
923
				</tr>
924
			</thead>
925
			<tbody>';
926
927
	foreach ($context['theme_files'] as $file)
928
	{
929
		echo '
930
				<tr class="windowbg">
931
					<td>';
932
933
		if ($file['is_editable'])
934
			echo '
935
						<a href="', $file['href'], '"', $file['is_template'] ? ' style="font-weight: bold;"' : '', '>', $file['filename'], '</a>';
936
937
		elseif ($file['is_directory'])
938
			echo '
939
						<a href="', $file['href'], '" class="is_directory"><span class="generic_icons folder"></span>', $file['filename'], '</a>';
940
941
		else
942
			echo $file['filename'];
943
944
		echo '
945
					</td>
946
					<td class="righttext">', !empty($file['last_modified']) ? $file['last_modified'] : '', '</td>
947
					<td class="righttext">', $file['size'], '</td>
948
				</tr>';
949
	}
950
951
	echo '
952
			</tbody>
953
		</table>';
954
}
955
956
/**
957
 * Wanna edit the stylesheet?
958
 */
959
function template_edit_style()
960
{
961
	global $context, $settings, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
962
963
	if ($context['session_error'])
964
		echo '
965
	<div class="errorbox">
966
		', $txt['error_session_timeout'], '
967
	</div>';
968
969
	// From now on no one can complain that editing css is difficult. If you disagree, go to www.w3schools.com.
970
	echo '
971
		<script>
972
			var previewData = "";
973
			var previewTimeout;
974
			var editFilename = ', JavaScriptEscape($context['edit_filename']), ';
975
976
			// Load up a page, but apply our stylesheet.
977
			function navigatePreview(url)
978
			{
979
				var myDoc = new XMLHttpRequest();
980
				myDoc.onreadystatechange = function ()
981
				{
982
					if (myDoc.readyState != 4)
983
						return;
984
985
					if (myDoc.responseText != null && myDoc.status == 200)
986
					{
987
						previewData = myDoc.responseText;
988
						document.getElementById("css_preview_box").style.display = "";
989
990
						// Revert to the theme they actually use ;).
991
						var tempImage = new Image();
992
						tempImage.src = smf_prepareScriptUrl(smf_scripturl) + "action=admin;area=theme;sa=edit;theme=', $settings['theme_id'], ';preview;" + (new Date().getTime());
993
994
						refreshPreviewCache = null;
995
						refreshPreview(false);
996
					}
997
				};
998
999
				var anchor = "";
1000
				if (url.indexOf("#") != -1)
1001
				{
1002
					anchor = url.substr(url.indexOf("#"));
1003
					url = url.substr(0, url.indexOf("#"));
1004
				}
1005
1006
				myDoc.open("GET", url + (url.indexOf("?") == -1 ? "?" : ";") + "theme=', $context['theme_id'], '" + anchor, true);
1007
				myDoc.send(null);
1008
			}
1009
			navigatePreview(smf_scripturl);
1010
1011
			var refreshPreviewCache;
1012
			function refreshPreview(check)
1013
			{
1014
				var identical = document.forms.stylesheetForm.entire_file.value == refreshPreviewCache;
1015
1016
				// Don\'t reflow the whole thing if nothing changed!!
1017
				if (check && identical)
1018
					return;
1019
				refreshPreviewCache = document.forms.stylesheetForm.entire_file.value;
1020
				// Replace the paths for images.
1021
				refreshPreviewCache = refreshPreviewCache.replace(/url\(\.\.\/images/gi, "url(" + smf_images_url);
1022
1023
				// Try to do it without a complete reparse.
1024
				if (identical)
1025
				{
1026
					try
1027
					{
1028
					';
1029
1030
	if (isBrowser('is_ie'))
1031
		echo '
1032
						var sheets = frames["css_preview_box"].document.styleSheets;
1033
						for (var j = 0; j < sheets.length; j++)
1034
						{
1035
							if (sheets[j].id == "css_preview_box")
1036
								sheets[j].cssText = document.forms.stylesheetForm.entire_file.value;
1037
						}';
1038
	else
1039
		echo '
1040
						setInnerHTML(frames["css_preview_box"].document.getElementById("css_preview_sheet"), document.forms.stylesheetForm.entire_file.value);';
1041
	echo '
1042
					}
1043
					catch (e)
1044
					{
1045
						identical = false;
1046
					}
1047
				}
1048
1049
				// This will work most of the time... could be done with an after-apply, maybe.
1050
				if (!identical)
1051
				{
1052
					var data = previewData + "";
1053
					var preview_sheet = document.forms.stylesheetForm.entire_file.value;
1054
					var stylesheetMatch = new RegExp(\'<link rel="stylesheet"[^>]+href="[^"]+\' + editFilename + \'[^>]*>\');
1055
1056
					// Replace the paths for images.
1057
					preview_sheet = preview_sheet.replace(/url\(\.\.\/images/gi, "url(" + smf_images_url);
1058
					data = data.replace(stylesheetMatch, "<style type=\"text/css\" id=\"css_preview_sheet\">" + preview_sheet + "<" + "/style>");
1059
1060
					frames["css_preview_box"].document.open();
1061
					frames["css_preview_box"].document.write(data);
1062
					frames["css_preview_box"].document.close();
1063
1064
					// Next, fix all its links so we can handle them and reapply the new css!
1065
					frames["css_preview_box"].onload = function ()
1066
					{
1067
						var fixLinks = frames["css_preview_box"].document.getElementsByTagName("a");
1068
						for (var i = 0; i < fixLinks.length; i++)
1069
						{
1070
							if (fixLinks[i].onclick)
1071
								continue;
1072
							fixLinks[i].onclick = function ()
1073
							{
1074
								window.parent.navigatePreview(this.href);
1075
								return false;
1076
							};
1077
						}
1078
					};
1079
				}
1080
			}
1081
		</script>
1082
		<iframe id="css_preview_box" name="css_preview_box" src="about:blank" frameborder="0" style="display: none;"></iframe>';
1083
1084
	// Just show a big box.... gray out the Save button if it's not saveable... (ie. not 777.)
1085
	echo '
1086
		<form action="', $scripturl, '?action=admin;area=theme;th=', $context['theme_id'], ';sa=edit" method="post" accept-charset="', $context['character_set'], '" name="stylesheetForm" id="stylesheetForm">
1087
			<div class="cat_bar">
1088
				<h3 class="catbg">', $txt['theme_edit'], ' - ', $context['edit_filename'], '</h3>
1089
			</div>
1090
			<div class="windowbg">';
1091
1092
	if (!$context['allow_save'])
1093
		echo '
1094
				', $txt['theme_edit_no_save'], ': ', $context['allow_save_filename'], '<br>';
1095
1096
	echo '
1097
				<textarea class="edit_file" name="entire_file" cols="80" rows="20" onkeyup="setPreviewTimeout();" onchange="refreshPreview(true);">', $context['entire_file'], '</textarea>
1098
				<br>
1099
				<div class="padding righttext">
1100
					<input type="submit" name="save" value="', $txt['theme_edit_save'], '"', $context['allow_save'] ? '' : ' disabled', ' class="button">
1101
					<input type="button" value="', $txt['themeadmin_edit_preview'], '" onclick="refreshPreview(false);" class="button">
1102
				</div>
1103
			</div>
1104
			<input type="hidden" name="filename" value="', $context['edit_filename'], '">
1105
			<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">';
1106
1107
	// Hopefully it exists.
1108 View Code Duplication
	if (isset($context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token']))
1109
		echo '
1110
			<input type="hidden" name="', $context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token_var'], '" value="', $context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token'], '">';
1111
1112
	echo '
1113
		</form>';
1114
}
1115
1116
/**
1117
 * This edits the template...
1118
 */
1119
function template_edit_template()
1120
{
1121
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1122
1123
	if ($context['session_error'])
1124
		echo '
1125
	<div class="errorbox">
1126
		', $txt['error_session_timeout'], '
1127
	</div>';
1128
1129
	if (isset($context['parse_error']))
1130
		echo '
1131
	<div class="errorbox">
1132
		', $txt['themeadmin_edit_error'], '
1133
		<div><pre>', $context['parse_error'], '</pre></div>
1134
	</div>';
1135
1136
	// Just show a big box.... gray out the Save button if it's not saveable... (ie. not 777.)
1137
	echo '
1138
		<form action="', $scripturl, '?action=admin;area=theme;th=', $context['theme_id'], ';sa=edit" method="post" accept-charset="', $context['character_set'], '">
1139
			<div class="cat_bar">
1140
				<h3 class="catbg">', $txt['theme_edit'], ' - ', $context['edit_filename'], '</h3>
1141
			</div>
1142
			<div class="windowbg">';
1143
1144
	if (!$context['allow_save'])
1145
		echo '
1146
				', $txt['theme_edit_no_save'], ': ', $context['allow_save_filename'], '<br>';
1147
1148
	foreach ($context['file_parts'] as $part)
1149
		echo '
1150
				<label for="on_line', $part['line'], '">', $txt['themeadmin_edit_on_line'], ' ', $part['line'], '</label>:<br>
1151
				<div class="centertext">
1152
					<textarea id="on_line', $part['line'], '" name="entire_file[]" cols="80" rows="', $part['lines'] > 14 ? '14' : $part['lines'], '" class="edit_file">', $part['data'], '</textarea>
1153
				</div>';
1154
1155
	echo '
1156
				<div class="padding righttext">
1157
					<input type="submit" name="save" value="', $txt['theme_edit_save'], '"', $context['allow_save'] ? '' : ' disabled', ' class="button">
1158
					<input type="hidden" name="filename" value="', $context['edit_filename'], '">
1159
					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">';
1160
1161
	// Hopefully it exists.
1162 View Code Duplication
	if (isset($context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token']))
1163
		echo '
1164
					<input type="hidden" name="', $context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token_var'], '" value="', $context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token'], '">';
1165
1166
	echo '
1167
				</div><!-- .righttext -->
1168
			</div><!-- .windowbg -->
1169
		</form>';
1170
}
1171
1172
/**
1173
 * This allows you to edit a file
1174
 */
1175
function template_edit_file()
1176
{
1177
	global $context, $scripturl, $txt;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1178
1179
	if ($context['session_error'])
1180
		echo '
1181
	<div class="errorbox">
1182
		', $txt['error_session_timeout'], '
1183
	</div>';
1184
1185
	// Is this file writeable?
1186
	if (!$context['allow_save'])
1187
		echo '
1188
	<div class="errorbox">
1189
		', $txt['theme_edit_no_save'], ': ', $context['allow_save_filename'], '
1190
	</div>';
1191
1192
	// Just show a big box.... gray out the Save button if it's not saveable... (ie. not 777.)
1193
	echo '
1194
		<form action="', $scripturl, '?action=admin;area=theme;th=', $context['theme_id'], ';sa=edit" method="post" accept-charset="', $context['character_set'], '">
1195
			<div class="cat_bar">
1196
				<h3 class="catbg">', $txt['theme_edit'], ' - ', $context['edit_filename'], '</h3>
1197
			</div>
1198
			<div class="windowbg">
1199
				<textarea name="entire_file" id="entire_file" cols="80" rows="20" class="edit_file">', $context['entire_file'], '</textarea><br>
1200
				<input type="submit" name="save" value="', $txt['theme_edit_save'], '"', $context['allow_save'] ? '' : ' disabled', ' class="button">
1201
				<input type="hidden" name="filename" value="', $context['edit_filename'], '">
1202
				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '">';
1203
1204
	// Hopefully it exists.
1205 View Code Duplication
	if (isset($context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token']))
1206
		echo '
1207
				<input type="hidden" name="', $context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token_var'], '" value="', $context['admin-te-' . md5($context['theme_id'] . '-' . $context['edit_filename']) . '_token'], '">';
1208
1209
	echo '
1210
			</div><!-- .windowbg -->
1211
		</form>';
1212
}
1213
1214
?>