Issues (3885)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

manager/actions/mutate_module.dynamic.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
if( ! defined('IN_MANAGER_MODE') || IN_MANAGER_MODE !== true) {
3
	die("<b>INCLUDE_ORDERING_ERROR</b><br /><br />Please use the EVO Content Manager instead of accessing this file directly.");
4
}
5 View Code Duplication
switch($modx->getManagerApi()->action) {
6
	case 107:
7
		if(!$modx->hasPermission('new_module')) {
8
			$modx->webAlertAndQuit($_lang["error_no_privileges"]);
9
		}
10
		break;
11
	case 108:
12
		if(!$modx->hasPermission('edit_module')) {
13
			$modx->webAlertAndQuit($_lang["error_no_privileges"]);
14
		}
15
		break;
16
	default:
17
		$modx->webAlertAndQuit($_lang["error_no_privileges"]);
18
}
19
$id = isset($_REQUEST['id']) ? (int)$_REQUEST['id'] : 0;
20
// Get table names (alphabetical)
21
$tbl_membergroup_names = $modx->getDatabase()->getFullTableName('membergroup_names');
22
$tbl_site_content = $modx->getDatabase()->getFullTableName('site_content');
23
$tbl_site_htmlsnippets = $modx->getDatabase()->getFullTableName('site_htmlsnippets');
24
$tbl_site_module_access = $modx->getDatabase()->getFullTableName('site_module_access');
25
$tbl_site_module_depobj = $modx->getDatabase()->getFullTableName('site_module_depobj');
26
$tbl_site_modules = $modx->getDatabase()->getFullTableName('site_modules');
27
$tbl_site_plugins = $modx->getDatabase()->getFullTableName('site_plugins');
28
$tbl_site_snippets = $modx->getDatabase()->getFullTableName('site_snippets');
29
$tbl_site_templates = $modx->getDatabase()->getFullTableName('site_templates');
30
$tbl_site_tmplvars = $modx->getDatabase()->getFullTableName('site_tmplvars');
31
32
33
// check to see the module editor isn't locked
34 View Code Duplication
if($lockedEl = $modx->elementIsLocked(6, $id)) {
35
	$modx->webAlertAndQuit(sprintf($_lang['lock_msg'], $lockedEl['username'], $_lang['module']));
36
}
37
// end check for lock
38
39
// Lock snippet for other users to edit
40
$modx->lockElement(6, $id);
41
42
if(isset($_GET['id'])) {
43
	$rs = $modx->getDatabase()->select('*', $tbl_site_modules, "id='{$id}'");
44
	$content = $modx->getDatabase()->getRow($rs);
45
	if(!$content) {
46
		$modx->webAlertAndQuit("Module not found for id '{$id}'.");
47
	}
48
	$content['properties'] = str_replace("&", "&amp;", $content['properties']);
49
	$_SESSION['itemname'] = $content['name'];
50 View Code Duplication
	if($content['locked'] == 1 && $_SESSION['mgrRole'] != 1) {
51
		$modx->webAlertAndQuit($_lang["error_no_privileges"]);
52
	}
53
} else {
54
	$_SESSION['itemname'] = $_lang["new_module"];
55
	$content['wrap'] = '1';
56
}
57
if($modx->getManagerApi()->hasFormValues()) {
58
	$modx->getManagerApi()->loadFormValues();
59
}
60
61
// Add lock-element JS-Script
62
$lockElementId = $id;
63
$lockElementType = 6;
64
require_once(MODX_MANAGER_PATH . 'includes/active_user_locks.inc.php');
65
?>
66
<script type="text/javascript">
67
	function loadDependencies() {
68
		if(documentDirty) {
69
			if(!confirm("<?= $_lang['confirm_load_depends']?>")) {
70
				return;
71
			}
72
		}
73
		documentDirty = false;
74
		window.location.href = "index.php?id=<?= $_REQUEST['id']?>&a=113";
75
	}
76
77
	var actions = {
78
		save: function() {
79
			documentDirty = false;
80
			form_save = true;
81
			document.mutate.save.click();
82
			saveWait('mutate');
83
		},
84
		duplicate: function() {
85
			if(confirm("<?= $_lang['confirm_duplicate_record'] ?>") === true) {
86
				documentDirty = false;
87
				document.location.href = "index.php?id=<?= $_REQUEST['id'] ?>&a=111";
88
			}
89
		},
90
		delete: function() {
91
			if(confirm("<?= $_lang['confirm_delete_module'] ?>") === true) {
92
				documentDirty = false;
93
				document.location.href = "index.php?id=" + document.mutate.id.value + "&a=110";
94
			}
95
		},
96
		cancel: function() {
97
			documentDirty = false;
98
			document.location.href = 'index.php?a=106';
99
		},
100
		run: function() {
101
			document.location.href = "index.php?id=<?= $_REQUEST['id'] ?>&a=112";
102
		}
103
	};
104
105
	function setTextWrap(ctrl, b) {
106
		if(!ctrl) return;
107
		ctrl.wrap = (b) ? "soft" : "off";
108
	}
109
110
	// Current Params/Configurations
111
	var currentParams = {};
112
	var internal = <?= json_encode($internal) ?>;
113
	var first = true;
114
115
	function showParameters(ctrl) {
116
		var c, p, df, cp;
117
		var ar, label, value, key, dt, defaultVal;
118
119
		currentParams = {}; // reset;
120
121
		if(ctrl && ctrl.form) {
122
			f = ctrl.form;
123
		} else {
124
			f = document.forms['mutate'];
125
			if(!f) return;
126
		}
127
128
		tr = (document.getElementById) ? document.getElementById('displayparamrow') : document.all['displayparamrow'];
129
130
		// check if codemirror is used
131
		var props = typeof myCodeMirrors != "undefined" && typeof myCodeMirrors['properties'] != "undefined" ? myCodeMirrors['properties'].getValue() : f.properties.value;
132
133
		// convert old schemed setup parameters
134
		if(!IsJsonString(props)) {
135
			dp = props ? props.match(/([^&=]+)=(.*?)(?=&[^&=]+=|$)/g) : ""; // match &paramname=
136
			if(!dp) tr.style.display = 'none';
137
			else {
138
				for(p = 0; p < dp.length; p++) {
139
					dp[p] = (dp[p] + '').replace(/^\s|\s$/, ""); // trim
140
					ar = dp[p].match(/(?:[^\=]|==)+/g); // split by =, not by ==
141
					key = ar[0];        // param
142
					ar = (ar[1] + '').split(";");
143
					label = ar[0];	    // label
144
					dt = ar[1];	    // data type
145
					value = decode((ar[2]) ? ar[2] : '');
146
147
					// convert values to new json-format
148
					if(key && (dt === 'menu' || dt === 'list' || dt === 'list-multi' || dt === 'checkbox' || dt === 'radio')) {
149
						defaultVal = decode((ar[4]) ? ar[4] : ar[3]);
150
						desc = decode((ar[5]) ? ar[5] : "");
151
						currentParams[key] = [];
152
						currentParams[key][0] = {"label": label, "type": dt, "value": ar[3], "options": value, "default": defaultVal, "desc": desc};
153
					} else if(key) {
154
						defaultVal = decode((ar[3]) ? ar[3] : ar[2]);
155
						desc = decode((ar[4]) ? ar[4] : "");
156
						currentParams[key] = [];
157
						currentParams[key][0] = {"label": label, "type": dt, "value": value, "default": defaultVal, "desc": desc};
158
					}
159
				}
160
			}
161
		} else {
162
			currentParams = JSON.parse(props);
163
		}
164
165
		t = '<table width="100%" class="displayparams grid"><thead><tr><td><?= $_lang['parameter'] ?></td><td><?= $_lang['value'] ?></td><td style="text-align:right;white-space:nowrap"><?= $_lang["set_default"] ?> </td></tr></thead>';
166
167
		try {
168
			var type, options, found, info, sd;
169
			var ll, ls, sets = [];
170
171
			Object.keys(currentParams).forEach(function(key) {
172
173
				if(key === 'internal' || currentParams[key][0]['label'] == undefined) return;
174
175
				cp = currentParams[key][0];
176
				type = cp['type'];
177
				value = cp['value'];
178
				defaultVal = cp['default'];
179
				label = cp['label'] != undefined ? cp['label'] : key;
180
				desc = cp['desc'] + '';
181
				options = cp['options'] != undefined ? cp['options'] : '';
182
183
				ll = [];
184
				ls = [];
185
				if(options.indexOf('==') > -1) {
186
					// option-format: label==value||label==value
187
					sets = options.split("||");
188
					for(i = 0; i < sets.length; i++) {
189
						split = sets[i].split("==");
190
						ll[i] = split[0];
191
						ls[i] = split[1] != undefined ? split[1] : split[0];
192
					}
193
				} else {
194
					// option-format: value,value
195
					ls = options.split(",");
196
					ll = ls;
197
				}
198
199
				switch(type) {
200
					case 'int':
201
						c = '<input type="text" name="prop_' + key + '" value="' + value + '" size="30" onchange="setParameter(\'' + key + '\',\'' + type + '\',this)" />';
202
						break;
203
					case 'menu':
204
						c = '<select name="prop_' + key + '" onchange="setParameter(\'' + key + '\',\'' + type + '\',this)">';
205
						if(currentParams[key] === options) currentParams[key] = ls[0]; // use first list item as default
206
						for(i = 0; i < ls.length; i++) {
207
							c += '<option value="' + ls[i] + '"' + ((ls[i] === value) ? ' selected="selected"' : '') + '>' + ll[i] + '</option>';
208
						}
209
						c += '</select>';
210
						break;
211
					case 'list':
212
						if(currentParams[key] === options) currentParams[key] = ls[0]; // use first list item as default
213
						c = '<select name="prop_' + key + '" size="' + ls.length + '" onchange="setParameter(\'' + key + '\',\'' + type + '\',this)">';
214
						for(i = 0; i < ls.length; i++) {
215
							c += '<option value="' + ls[i] + '"' + ((ls[i] === value) ? ' selected="selected"' : '') + '>' + ll[i] + '</option>';
216
						}
217
						c += '</select>';
218
						break;
219
					case 'list-multi':
220
						// value = typeof ar[3] !== 'undefined' ? (ar[3] + '').replace(/^\s|\s$/, "") : '';
221
						arrValue = value.split(",");
222
						if(currentParams[key] === options) currentParams[key] = ls[0]; // use first list item as default
223
						c = '<select name="prop_' + key + '" size="' + ls.length + '" multiple="multiple" onchange="setParameter(\'' + key + '\',\'' + type + '\',this)">';
224
						for(i = 0; i < ls.length; i++) {
225
							if(arrValue.length) {
226
								found = false;
227
								for(j = 0; j < arrValue.length; j++) {
228
									if(ls[i] === arrValue[j]) {
229
										found = true;
230
									}
231
								}
232
								if(found === true) {
233
									c += '<option value="' + ls[i] + '" selected="selected">' + ll[i] + '</option>';
234
								} else {
235
									c += '<option value="' + ls[i] + '">' + ll[i] + '</option>';
236
								}
237
							} else {
238
								c += '<option value="' + ls[i] + '">' + ll[i] + '</option>';
239
							}
240
						}
241
						c += '</select>';
242
						break;
243
					case 'checkbox':
244
						lv = (value + '').split(",");
245
						c = '';
246
						for(i = 0; i < ls.length; i++) {
247
							c += '<label><input type="checkbox" name="prop_' + key + '[]" value="' + ls[i] + '"' + ((contains(lv, ls[i]) == true) ? ' checked="checked"' : '') + ' onchange="setParameter(\'' + key + '\',\'' + type + '\',this)" />' + ll[i] + '</label>&nbsp;';
248
						}
249
						break;
250
					case 'radio':
251
						c = '';
252
						for(i = 0; i < ls.length; i++) {
253
							c += '<label><input type="radio" name="prop_' + key + '" value="' + ls[i] + '"' + ((ls[i] === value) ? ' checked="checked"' : '') + ' onchange="setParameter(\'' + key + '\',\'' + type + '\',this)" />' + ll[i] + '</label>&nbsp;';
254
						}
255
						break;
256
					case 'textarea':
257
						c = '<textarea name="prop_' + key + '" rows="4" onchange="setParameter(\'' + key + '\',\'' + type + '\',this)">' + value + '</textarea>';
258
						break;
259
					default:  // string
260
						c = '<input type="text" name="prop_' + key + '" value="' + value + '" onchange="setParameter(\'' + key + '\',\'' + type + '\',this)" />';
261
						break;
262
				}
263
264
				info = '';
265
				info += desc ? '<br/><small>' + desc + '</small>' : '';
266
				sd = defaultVal != undefined ? '<a title="<?= $_lang["set_default"] ?>" href="javascript:;" class="btn btn-primary" onclick="setDefaultParam(\'' + key + '\',1);return false;"><i class="fa fa-refresh"></i></a>' : '';
267
268
				t += '<tr><td class="labelCell" width="20%"><span class="paramLabel">' + label + '</span><span class="paramDesc">' + info + '</span></td><td class="inputCell relative" width="74%">' + c + '</td><td style="text-align: center">' + sd + '</td></tr>';
269
			});
270
271
			t += '</table>';
272
273
		} catch(e) {
274
			t = e + "\n\n" + props;
275
		}
276
277
		td = (document.getElementById) ? document.getElementById('displayparams') : document.all['displayparams'];
278
		td.innerHTML = t;
279
		tr.style.display = '';
280
281
		implodeParameters();
282
	}
283
284
	function setParameter(key, dt, ctrl) {
285
		var v;
286
		var arrValues, cboxes = [];
287
		if(!ctrl) return null;
288
		switch(dt) {
289
			case 'int':
290
				ctrl.value = parseInt(ctrl.value);
291
				if(isNaN(ctrl.value)) ctrl.value = 0;
292
				v = ctrl.value;
293
				break;
294
			case 'menu':
295
			case 'list':
296
				v = ctrl.options[ctrl.selectedIndex].value;
297
				break;
298
			case 'list-multi':
299
				arrValues = [];
300
				for(var i = 0; i < ctrl.options.length; i++) {
301
					if(ctrl.options[i].selected) {
302
						arrValues.push(ctrl.options[i].value);
303
					}
304
				}
305
				v = arrValues.toString();
306
				break;
307
			case 'checkbox':
308
				arrValues = [];
309
				cboxes = document.getElementsByName(ctrl.name);
310
				for(var i = 0; i < cboxes.length; i++) {
311
					if(cboxes[i].checked) {
312
						arrValues.push(cboxes[i].value);
313
					}
314
				}
315
				v = arrValues.toString();
316
				break;
317
			default:
318
				v = ctrl.value + '';
319
				break;
320
		}
321
		currentParams[key][0]['value'] = v;
322
		implodeParameters();
323
	}
324
325
	// implode parameters
326
	function implodeParameters() {
327
		var stringified = JSON.stringify(currentParams, null, 2);
328
		if(typeof myCodeMirrors != "undefined") {
329
			myCodeMirrors['properties'].setValue(stringified);
330
		} else {
331
			f.properties.value = stringified;
332
		}
333
		if(first) {
334
			documentDirty = false;
335
			first = false;
336
		}
337
		;
338
	}
339
340
	function encode(s) {
341
		s = s + '';
342
		s = s.replace(/\=/g, '%3D'); // =
343
		s = s.replace(/\&/g, '%26'); // &
344
		return s;
345
	}
346
347
	function decode(s) {
348
		s = s + '';
349
		s = s.replace(/\%3D/g, '='); // =
350
		s = s.replace(/\%26/g, '&'); // &
351
		return s;
352
	}
353
354
	/**
355
	 * @return {boolean}
356
	 */
357
	function IsJsonString(str) {
358
		try {
359
			JSON.parse(str);
360
		} catch(e) {
361
			return false;
362
		}
363
		return true;
364
	}
365
366
	function setDefaultParam(key, show) {
367
		if(typeof currentParams[key][0]['default'] != 'undefined') {
368
			currentParams[key][0]['value'] = currentParams[key][0]['default'];
369
			if(show) {
370
				implodeParameters();
371
				showParameters();
372
			}
373
		}
374
	}
375
376
	function setDefaults() {
377
		var keys = Object.keys(currentParams);
378
		var last = keys[keys.length - 1],
379
			show;
380
		Object.keys(currentParams).forEach(function(key) {
381
			show = key === last ? 1 : 0;
382
			setDefaultParam(key, show);
383
		});
384
	}
385
386
	function contains(a, obj) {
387
		var i = a.length;
388
		while(i--) {
389
			if(a[i] === obj) {
390
				return true;
391
			}
392
		}
393
		return false;
394
	}
395
396
	// Resource browser
397
	function OpenServerBrowser(url, width, height) {
398
		var iLeft = (screen.width - width) / 2;
399
		var iTop = (screen.height - height) / 2;
400
		var sOptions = "toolbar=no,status=no,resizable=yes,dependent=yes";
401
		sOptions += ",width=" + width;
402
		sOptions += ",height=" + height;
403
		sOptions += ",left=" + iLeft;
404
		sOptions += ",top=" + iTop;
405
		var oWindow = window.open(url, "FCKBrowseWindow", sOptions);
406
	}
407
408
	function BrowseServer() {
409
		var w = screen.width * 0.7;
410
		var h = screen.height * 0.7;
411
		OpenServerBrowser("<?= MODX_MANAGER_URL;?>media/browser/<?= $which_browser;?>/browser.php?Type=images", w, h);
0 ignored issues
show
It is generally recommended to place each PHP statement on a line by itself.

Let’s take a look at an example:

// Bad
$a = 5; $b = 6; $c = 7;

// Good
$a = 5;
$b = 6;
$c = 7;
Loading history...
412
	}
413
414
	function SetUrl(url, width, height, alt) {
415
		document.mutate.icon.value = url;
416
	}
417
418
	document.addEventListener('DOMContentLoaded', function() {
419
		var h1help = document.querySelector('h1 > .help');
420
		h1help.onclick = function() {
421
			document.querySelector('.element-edit-message').classList.toggle('show')
422
		}
423
	});
424
425
</script>
426
427
<form name="mutate" id="mutate" class="module" method="post" action="index.php?a=109">
428
	<?php
429
	// invoke OnModFormPrerender event
430
	$evtOut = $modx->invokeEvent('OnModFormPrerender', array('id' => $id));
431
	if(is_array($evtOut)) {
432
		echo implode('', $evtOut);
433
	}
434
435
	// Prepare internal params & info-tab via parseDocBlock
436
	$modulecode = isset($content['modulecode']) ? $modx->getDatabase()->escape($content['modulecode']) : '';
437
	$docBlock = $modx->parseDocBlockFromString($modulecode);
438
	$docBlockList = $modx->convertDocBlockIntoList($docBlock);
439
	$internal = array();
440
	?>
441
	<input type="hidden" name="id" value="<?= $content['id'] ?>">
442
	<input type="hidden" name="mode" value="<?= $modx->getManagerApi()->action ?>">
443
444
	<h1>
445
		<i class="<?= ($content['icon'] != '' ? $content['icon'] : $_style['icons_module']) ?>"></i><?= ($content['name'] ? $content['name'] . '<small>(' . $content['id'] . ')</small>' : $_lang['new_module']) ?><i class="fa fa-question-circle help"></i>
446
	</h1>
447
448
	<?= ManagerTheme::getStyle('actionbuttons.dynamic.element') ?>
449
450
	<div class="container element-edit-message">
451
		<div class="alert alert-info"><?= $_lang['module_msg'] ?></div>
452
	</div>
453
454
	<div class="tab-pane" id="modulePane">
455
		<script type="text/javascript">
456
			tp = new WebFXTabPane(document.getElementById("modulePane"), <?= ($modx->config['remember_last_tab'] == 1 ? 'true' : 'false') ?> );
457
		</script>
458
459
		<!-- General -->
460
		<div class="tab-page" id="tabModule">
461
			<h2 class="tab"><?= $_lang['settings_general'] ?></h2>
462
			<script type="text/javascript">tp.addTabPage(document.getElementById("tabModule"));</script>
463
			<div class="container container-body">
464
				<div class="form-group">
465
					<div class="row form-row">
466
						<label class="col-md-3 col-lg-2"><?= $_lang['module_name'] ?></label>
467
						<div class="col-md-9 col-lg-10">
468
							<div class="form-control-name clearfix">
469
								<input name="name" type="text" maxlength="100" value="<?= $modx->getPhpCompat()->htmlspecialchars($content['name']) ?>" class="form-control form-control-lg" onchange="documentDirty=true;" />
470
								<?php if($modx->hasPermission('save_role')): ?>
471
									<label class="custom-control" title="<?= $_lang['lock_module'] . "\n" . $_lang['lock_module_msg'] ?>" tooltip>
472
										<input name="locked" type="checkbox"<?= ($content['locked'] == 1 ? ' checked="checked"' : '') ?> />
473
										<i class="fa fa-lock"></i>
474
									</label>
475
								<?php endif; ?>
476
							</div>
477
							<script>if(!document.getElementsByName("name")[0].value) document.getElementsByName("name")[0].focus();</script>
478
							<small class="form-text text-danger hide" id="savingMessage"></small>
479
						</div>
480
					</div>
481
					<div class="row form-row">
482
						<label class="col-md-3 col-lg-2"><?= $_lang['module_desc'] ?></label>
483
						<div class="col-md-9 col-lg-10">
484
							<input name="description" type="text" maxlength="255" value="<?= $content['description'] ?>" class="form-control" onchange="documentDirty=true;" />
485
						</div>
486
					</div>
487
					<div class="row form-row">
488
						<label class="col-md-3 col-lg-2"><?= $_lang['existing_category'] ?></label>
489
						<div class="col-md-9 col-lg-10">
490
							<select name="categoryid" class="form-control" onchange="documentDirty=true;">
491
								<option>&nbsp;</option>
492
								<?php
493
								include_once(MODX_MANAGER_PATH . 'includes/categories.inc.php');
494
								foreach(getCategories() as $n => $v) {
495
									echo "\t\t\t" . '<option value="' . $v['id'] . '"' . ($content['category'] == $v['id'] ? ' selected="selected"' : '') . '>' . $modx->getPhpCompat()->htmlspecialchars($v['category']) . "</option>\n";
496
								}
497
								?>
498
							</select>
499
						</div>
500
					</div>
501
					<div class="row form-row">
502
						<label class="col-md-3 col-lg-2"><?= $_lang['new_category'] ?></label>
503
						<div class="col-md-9 col-lg-10">
504
							<input name="newcategory" type="text" maxlength="45" value="" class="form-control" onchange="documentDirty=true;" />
505
						</div>
506
					</div>
507
					<div class="row form-row">
508
						<label class="col-md-3 col-lg-2"><?= $_lang['icon'] ?>
509
							<small class="text-muted"><?= $_lang["icon_description"] ?></small>
510
						</label>
511
						<div class="col-md-9 col-lg-10">
512
							<div class="input-group">
513
								<input type="text" maxlength="255" name="icon" value="<?= $content['icon'] ?>" class="form-control" onchange="documentDirty=true;" />
514
							</div>
515
						</div>
516
					</div>
517
					<div class="row form-row">
518
						<label class="col-md-3 col-lg-2" for="enable_resource"><input name="enable_resource" id="enable_resource" title="<?= $_lang['enable_resource'] ?>" type="checkbox"<?= ($content['enable_resource'] == 1 ? ' checked="checked"' : '') ?> onclick="documentDirty=true;" /> <span title="<?= $_lang['enable_resource'] ?>"><?= $_lang["element"] ?></span></label>
519
						<div class="col-md-9 col-lg-10">
520
							<input name="resourcefile" type="text" maxlength="255" value="<?= $content['resourcefile'] ?>" class="form-control" onchange="documentDirty=true;" />
521
						</div>
522
					</div>
523
				</div>
524
				<div class="form-group">
525
					<div class="form-row">
526
						<label for="disabled"><input name="disabled" id="disabled" type="checkbox" value="on"<?= ($content['disabled'] == 1 ? ' checked="checked"' : '') ?> />
527
							<?= ($content['disabled'] == 1 ? '<span class="text-danger">' . $_lang['module_disabled'] . '</span>' : $_lang['module_disabled']) ?></label>
528
					</div>
529
					<div class="form-row">
530
						<label for="parse_docblock">
531
							<input name="parse_docblock" id="parse_docblock" type="checkbox" value="1"<?= ($modx->getManagerApi()->action == 107 ? ' checked="checked"' : '') ?> /> <?= $_lang['parse_docblock'] ?></label>
532
						<small class="form-text text-muted"><?= $_lang['parse_docblock_msg'] ?></small>
533
					</div>
534
				</div>
535
			</div>
536
537
			<!-- PHP text editor start -->
538
			<div class="navbar navbar-editor">
539
				<span><?= $_lang['module_code'] ?></span>
540
			</div>
541
			<div class="section-editor clearfix">
542
				<textarea dir="ltr" class="phptextarea" name="post" rows="20" wrap="soft" onchange="documentDirty=true;"><?= $modx->getPhpCompat()->htmlspecialchars($content['modulecode']) ?></textarea>
543
			</div>
544
			<!-- PHP text editor end -->
545
		</div>
546
547
		<!-- Configuration -->
548
		<div class="tab-page" id="tabConfig">
549
			<h2 class="tab"><?= $_lang["settings_config"] ?></h2>
550
			<script type="text/javascript">tp.addTabPage(document.getElementById("tabConfig"));</script>
551
			<div class="container container-body">
552
				<div class="form-group">
553
					<a href="javascript:;" class="btn btn-primary" onclick="setDefaults(this);return false;"><?= $_lang['set_default_all'] ?></a>
554
				</div>
555
				<div id="displayparamrow">
556
					<div id="displayparams"></div>
557
				</div>
558
			</div>
559
		</div>
560
561
		<!-- Properties -->
562
		<div class="tab-page" id="tabParams">
563
			<h2 class="tab"><?= $_lang['settings_properties'] ?></h2>
564
			<script type="text/javascript">tp.addTabPage(document.getElementById("tabParams"));</script>
565
			<div class="container container-body">
566
				<div class="form-group">
567
					<div class="row form-row">
568
						<label class="col-md-3 col-lg-2"><?= $_lang['guid'] ?></label>
569
						<div class="col-md-9 col-lg-10">
570
							<input name="guid" type="text" maxlength="32" value="<?= ($modx->getManagerApi()->action == 107 ? createGUID() : $content['guid']) ?>" class="form-control" onchange="documentDirty=true;" />
571
							<small class="form-text text-muted"><?= $_lang['import_params_msg'] ?></small>
572
						</div>
573
					</div>
574
					<div class="row form-row">
575
						<label class="col-md-3 col-lg-2" for="enable_sharedparams">
576
							<input name="enable_sharedparams" id="enable_sharedparams" type="checkbox"<?= ($content['enable_sharedparams'] == 1 ? ' checked="checked"' : '') ?> onclick="documentDirty=true;" /> <?= $_lang['enable_sharedparams'] ?></label>
577
						<div class="col-md-9 col-lg-10">
578
							<small class="form-text text-muted"><?= $_lang['enable_sharedparams_msg'] ?></small>
579
						</div>
580
					</div>
581
				</div>
582
				<div class="form-group">
583
					<a href="javascript:;" class="btn btn-primary" onclick="tp.pages[1].select();showParameters(this);return false;"><?= $_lang['update_params'] ?></a>
584
				</div>
585
			</div>
586
			<!-- HTML text editor start -->
587
			<div class="section-editor clearfix">
588
				<textarea dir="ltr" name="properties" class="phptextarea" rows="20" wrap="soft" onChange="showParameters(this);documentDirty=true;"><?= $content['properties'] ?></textarea>
589
			</div>
590
			<!-- HTML text editor end -->
591
		</div>
592
		<?php if($modx->getManagerApi()->action == '108'): ?>
593
			<!-- Dependencies -->
594
			<div class="tab-page" id="tabDepend">
595
				<h2 class="tab"><?= $_lang['settings_dependencies'] ?></h2>
596
				<script type="text/javascript">tp.addTabPage(document.getElementById("tabDepend"));</script>
597
				<div class="container container-body">
598
					<p><?= $_lang['module_viewdepend_msg'] ?></p>
599
					<div class="form-group clearfix">
600
						<a class="btn btn-primary" href="javascript:;" onclick="loadDependencies();return false;">
601
							<i class="<?= $_style["actions_save"] ?>"></i> <?= $_lang['manage_depends'] ?></a>
602
					</div>
603
					<?php
604
					$ds = $modx->getDatabase()->select("smd.id, COALESCE(ss.name,st.templatename,sv.name,sc.name,sp.name,sd.pagetitle) AS name, 
605
					CASE smd.type
606
						WHEN 10 THEN 'Chunk'
607
						WHEN 20 THEN 'Document'
608
						WHEN 30 THEN 'Plugin'
609
						WHEN 40 THEN 'Snippet'
610
						WHEN 50 THEN 'Template'
611
						WHEN 60 THEN 'TV'
612
					END AS type", "{$tbl_site_module_depobj} AS smd 
613
						LEFT JOIN {$tbl_site_htmlsnippets} AS sc ON sc.id = smd.resource AND smd.type = 10 
614
						LEFT JOIN {$tbl_site_content} AS sd ON sd.id = smd.resource AND smd.type = 20
615
						LEFT JOIN {$tbl_site_plugins} AS sp ON sp.id = smd.resource AND smd.type = 30
616
						LEFT JOIN {$tbl_site_snippets} AS ss ON ss.id = smd.resource AND smd.type = 40
617
						LEFT JOIN {$tbl_site_templates} AS st ON st.id = smd.resource AND smd.type = 50
618
						LEFT JOIN {$tbl_site_tmplvars} AS sv ON sv.id = smd.resource AND smd.type = 60", "smd.module='{$id}'", 'smd.type,name');
619
620
					$grd = new \EvolutionCMS\Support\DataGrid('', $ds, 0); // set page size to 0 t show all items
621
					$grd->noRecordMsg = $_lang['no_records_found'];
622
					$grd->cssClass = 'grid';
623
					$grd->columnHeaderClass = 'gridHeader';
624
					$grd->itemClass = 'gridItem';
625
					$grd->altItemClass = 'gridAltItem';
626
					$grd->columns = $_lang['element_name'] . " ," . $_lang['type'];
627
					$grd->fields = "name,type";
628
					echo $grd->render();
629
					?>
630
				</div>
631
			</div>
632
		<?php endif; ?>
633
634
		<!-- access permission -->
635
		<div class="tab-page" id="tabPermissions">
636
			<h2 class="tab"><?= $_lang['access_permissions'] ?></h2>
637
			<script type="text/javascript">tp.addTabPage(document.getElementById("tabPermissions"));</script>
638
			<div class="container container-body">
639
				<?php if($modx->getConfig('use_udperms')) : ?>
640
					<?php
641
					// fetch user access permissions for the module
642
					$rs = $modx->getDatabase()->select('usergroup', $tbl_site_module_access, "module='{$id}'");
643
					$groupsarray = $modx->getDatabase()->getColumn('usergroup', $rs);
644
645
					if($modx->hasPermission('access_permissions')) {
646
						?>
647
						<!-- User Group Access Permissions -->
648
						<script type="text/javascript">
649
							function makePublic(b) {
650
								var notPublic = false;
651
								var f = document.forms['mutate'];
652
								var chkpub = f['chkallgroups'];
653
								var chks = f['usrgroups[]'];
654
								if(!chks && chkpub) {
655
									chkpub.checked = true;
656
									return false;
657
								} else if(!b && chkpub) {
658
									if(!chks.length) notPublic = chks.checked;
659
									else for(i = 0; i < chks.length; i++) if(chks[i].checked) notPublic = true;
660
									chkpub.checked = !notPublic;
661
								} else {
662
									if(!chks.length) chks.checked = (b) ? false : chks.checked;
663
									else for(i = 0; i < chks.length; i++) if(b) chks[i].checked = false;
664
									chkpub.checked = true;
665
								}
666
							}
667
						</script>
668
						<p><?= $_lang['module_group_access_msg'] ?></p>
669
						<?php
670
					}
671
					$chk = '';
672
					$rs = $modx->getDatabase()->select('name, id', $tbl_membergroup_names, '', 'name');
673
					while($row = $modx->getDatabase()->getRow($rs)) {
674
						$groupsarray = is_numeric($id) && $id > 0 ? $groupsarray : array();
675
						$checked = in_array($row['id'], $groupsarray);
676
						if($modx->hasPermission('access_permissions')) {
677
							if($checked) {
678
								$notPublic = true;
679
							}
680
							$chks .= '<label><input type="checkbox" name="usrgroups[]" value="' . $row['id'] . '"' . ($checked ? ' checked="checked"' : '') . ' onclick="makePublic(false)" /> ' . $row['name'] . "</label><br />\n";
681
						} else {
682
							if($checked) {
683
								$chks = '<input type="hidden" name="usrgroups[]"  value="' . $row['id'] . '" />' . "\n" . $chks;
684
							}
685
						}
686
					}
687 View Code Duplication
					if($modx->hasPermission('access_permissions')) {
688
						$chks = '<label><input type="checkbox" name="chkallgroups"' . (!$notPublic ? ' checked="checked"' : '') . ' onclick="makePublic(true)" /><span class="warning"> ' . $_lang['all_usr_groups'] . '</span></label><br />' . "\n" . $chks;
689
					}
690
					echo $chks;
691
					?>
692
				<?php endif; ?>
693
			</div>
694
		</div>
695
696
		<!-- docBlock Info -->
697
		<div class="tab-page" id="tabDocBlock">
698
			<h2 class="tab"><?= $_lang['information'] ?></h2>
699
			<script type="text/javascript">tp.addTabPage(document.getElementById("tabDocBlock"));</script>
700
			<div class="container container-body">
701
				<?= $docBlockList ?>
702
			</div>
703
		</div>
704
705
		<input type="submit" name="save" style="display:none;">
706
		<?php
707
		// invoke OnModFormRender event
708
		$evtOut = $modx->invokeEvent('OnModFormRender', array('id' => $id));
709
		if(is_array($evtOut)) {
710
			echo implode('', $evtOut);
711
		}
712
		?>
713
</form>
714
<script type="text/javascript">setTimeout('showParameters();', 10);</script>
715