Project

General

Profile

Download (11.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/* ====================================================================
2
 *	Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
3
 *
4
 *	Redistribution and use in source and binary forms, with or without modification,
5
 *	are permitted provided that the following conditions are met:
6
 *
7
 *	1. Redistributions of source code must retain the above copyright notice,
8
 *		this list of conditions and the following disclaimer.
9
 *
10
 *	2. Redistributions in binary form must reproduce the above copyright
11
 *		notice, this list of conditions and the following disclaimer in
12
 *		the documentation and/or other materials provided with the
13
 *		distribution.
14
 *
15
 *	3. All advertising materials mentioning features or use of this software
16
 *		must display the following acknowledgment:
17
 *		"This product includes software developed by the pfSense Project
18
 *		 for use in the pfSense software distribution. (http://www.pfsense.org/).
19
 *
20
 *	4. The names "pfSense" and "pfSense Project" must not be used to
21
 *		 endorse or promote products derived from this software without
22
 *		 prior written permission. For written permission, please contact
23
 *		 coreteam@pfsense.org.
24
 *
25
 *	5. Products derived from this software may not be called "pfSense"
26
 *		nor may "pfSense" appear in their names without prior written
27
 *		permission of the Electric Sheep Fencing, LLC.
28
 *
29
 *	6. Redistributions of any form whatsoever must retain the following
30
 *		acknowledgment:
31
 *
32
 *	"This product includes software developed by the pfSense Project
33
 *	for use in the pfSense software distribution (http://www.pfsense.org/).
34
 *
35
 *	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
36
 *	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38
 *	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
39
 *	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40
 *	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41
 *	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44
 *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45
 *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46
 *	OF THE POSSIBILITY OF SUCH DAMAGE.
47
 *
48
 *	====================================================================
49
 *
50
 */
51

    
52
// These helper functions are used on many/most UI pages to hide/show/disable/enable form elements where required
53

    
54
// Hides the <div> in which the specified input element lives so that the input, its label and help text are hidden
55
function hideInput(id, hide) {
56
	if(hide)
57
		$('#' + id).parent().parent('div').addClass('hidden');
58
	else
59
		$('#' + id).parent().parent('div').removeClass('hidden');
60
}
61

    
62
// Hides the <div> in which the specified group input element lives so that the input,
63
// its label and help text are hidden
64
function hideGroupInput(id, hide) {
65
	if(hide)
66
		$('#' + id).parent('div').addClass('hidden');
67
	else
68
		$('#' + id).parent('div').removeClass('hidden');
69
}
70

    
71
// Hides the <div> in which the specified checkbox lives so that the checkbox, its label and help text are hidden
72
function hideCheckbox(id, hide) {
73
	if(hide)
74
		$('#' + id).parent().parent().parent('div').addClass('hidden');
75
	else
76
		$('#' + id).parent().parent().parent('div').removeClass('hidden');
77
}
78

    
79
// Disables the specified input element
80
function disableInput(id, disable) {
81
	$('#' + id).prop("disabled", disable);
82
}
83

    
84
// Hides all elements of the specified class. This will usually be a section
85
function hideClass(s_class, hide) {
86
	if(hide)
87
		$('.' + s_class).hide();
88
	else
89
		$('.' + s_class).show();
90
}
91

    
92
// Hides all elements of the specified class assigned to a group. This will usually be a group
93
function hideGroupClass(s_class, hide) {
94
	if(hide)
95
		$('.' + s_class).parent().parent().parent().hide();
96
	else
97
		$('.' + s_class).parent().parent().parent().show();
98
}
99

    
100
function hideSelect(id, hide) {
101
	if(hide)
102
		$('#' + id).parent('div').parent('div').addClass('hidden');
103
	else
104
		$('#' + id).parent('div').parent('div').removeClass('hidden');
105
}
106

    
107
function hideMultiCheckbox(id, hide) {
108
	if(hide)
109
		$('#' + id).parent().addClass('hidden');
110
	else
111
		$('#' + id).parent().removeClass('hidden');
112
}
113

    
114
// Hides the <div> in which the specified IP address element lives so that the input, its label and help text are hidden
115
function hideIpAddress(id, hide) {
116
	if(hide)
117
		$('#' + id).parent().parent().parent('div').addClass('hidden');
118
	else
119
		$('#' + id).parent().parent().parent('div').removeClass('hidden');
120
}
121

    
122
// Hides all elements of the specified class belonging to a multiselect.
123
function hideMultiClass(s_class, hide) {
124
	if(hide)
125
		$('.' + s_class).parent().parent().hide();
126
	else
127
		$('.' + s_class).parent().parent().show();
128
}
129

    
130
// Hides div whose label contains the specified text. (Good for StaticText)
131
function hideLabel(text, hide) {
132

    
133
	var element = $('label:contains(' + text + ')');
134

    
135
	if(hide)
136
		element.parent('div').addClass('hidden');
137
	else
138
		element.parent('div').removeClass('hidden');
139
}
140

    
141
// Toggle table row chackboxes and background colors on the pages that use sortable tables:
142
//	/usr/local/www/firewall_nat.php
143
//	/usr/local/www/firewall_nat_1to1.php
144
//	/usr/local/www/firewall_nat_out.php
145
//	/usr/local/www/firewall_rules.php
146
//	/usr/local/www/vpn_ipsec.php
147
// Striping of the tables is handled here, NOT with the Bootstrap table-striped class because it would
148
// get confused when rows are sorted or deleted.
149

    
150
function stripe_table() {
151
	$("tr:odd").addClass('active');
152
	$("tr:even").removeClass('active');
153
}
154

    
155
function fr_toggle(id, prefix) {
156
	if (!prefix)
157
		prefix = 'fr';
158

    
159
	var checkbox = document.getElementById(prefix + 'c' + id);
160
	checkbox.checked = !checkbox.checked;
161
	fr_bgcolor(id, prefix);
162
}
163

    
164
// Change background color based on state of checkbox
165
// On resetting background, reapply table striping
166
function fr_bgcolor(id, prefix) {
167
	if (!prefix)
168
		prefix = 'fr';
169

    
170
	var row = $('#' + prefix + id);
171

    
172
	if ($('#' + prefix + 'c' + id).prop('checked') ) {
173
		row.css("background-color", "#DDF4FF");
174
		row.removeClass('active');
175
	} else {
176
		row.css("background-color", "#FFFFFF");
177
		stripe_table();
178
	}
179
}
180

    
181
// The following functions are used by Form_Groups assigned a class of "repeatable" and provide the ability
182
// to add/delete rows of sequentially numbered elements, their labels and their help text
183
// See firewall_aliases_edit.php for an example
184

    
185
// NOTE: retainhelp is a global var that defined prevents any help text from being deleted as lines are inserted.
186
// IOW it causes every row to have help text, not just the last row
187

    
188
function setMasks() {
189
	// Find all ipaddress masks and make dynamic based on address family of input
190
	$('span.pfIpMask + select').each(function (idx, select){
191
		var input = $(select).prevAll('input[type=text]');
192

    
193
		input.on('change', function(e){
194
			var isV6 = (input.val().indexOf(':') != -1), min = 0, max = 128;
195
			if (!isV6)
196
				max = 32;
197

    
198
			if (input.val() == "")
199
				return;
200

    
201
			while (select.options.length > max)
202
				select.remove(0);
203

    
204
			if (select.options.length < max)
205
			{
206
				for (var i=select.options.length; i<=max; i++)
207
					select.options.add(new Option(i, i), 0);
208
			}
209
		});
210

    
211
		// Fire immediately
212
		input.change();
213
	});
214
}
215

    
216
// Complicated function to move all help text associated with this input id to the same id
217
// on the row above. That way if you delete the last row, you don't lose the help
218
function moveHelpText(id) {
219
	$('#' + id).parent('div').parent('div').find('input').each(function() {	 // For each <span></span>
220
		var fromId = this.id;
221
		var toId = decrStringInt(fromId);
222
		var helpSpan;
223

    
224
		if(!$(this).hasClass('pfIpMask') && !$(this).hasClass('btn')) {
225

    
226
			helpSpan = $('#' + fromId).parent('div').parent('div').find('span:last').clone();
227
			if($(helpSpan).hasClass('help-block')) {
228
				if($('#' + decrStringInt(fromId)).parent('div').hasClass('input-group'))
229
					$('#' + decrStringInt(fromId)).parent('div').after(helpSpan);
230
				else
231
					$('#' + decrStringInt(fromId)).after(helpSpan);
232
			}
233
		}
234
	});
235
}
236

    
237
// Increment the number at the end of the string
238
function bumpStringInt( str )	{
239
  var data = str.match(/(\D*)(\d+)(\D*)/), newStr = "";
240

    
241
  if( data )
242
	newStr = data[ 1 ] + ( Number( data[ 2 ] ) + 1 ) + data[ 3 ];
243

    
244
  return newStr || str;
245
}
246

    
247
// Decrement the number at the end of the string
248
function decrStringInt( str )	{
249
  var data = str.match(/(\D*)(\d+)(\D*)/), newStr = "";
250

    
251
  if( data )
252
	newStr = data[ 1 ] + ( Number( data[ 2 ] ) - 1 ) + data[ 3 ];
253

    
254
  return newStr || str;
255
}
256

    
257
// Called after a delete so that there are no gaps in the numbering. Most of the time the config system doesn't care about
258
// gaps, but I do :)
259
function renumber() {
260
	var idx = 0;
261

    
262
	$('.repeatable').each(function() {
263

    
264
		$(this).find('input').each(function() {
265
			$(this).prop("id", this.id.replace(/\d+$/, "") + idx);
266
			$(this).prop("name", this.name.replace(/\d+$/, "") + idx);
267
		});
268

    
269
		$(this).find('select').each(function() {
270
			$(this).prop("id", this.id.replace(/\d+$/, "") + idx);
271
			$(this).prop("name", this.name.replace(/\d+$/, "") + idx);
272
		});
273

    
274
		$(this).find('label').attr('for', $(this).find('label').attr('for').replace(/\d+$/, "") + idx);
275

    
276
		idx++;
277
	});
278
}
279

    
280
function delete_row(row) {
281
	$('#' + row).parent('div').parent('div').remove();
282
	renumber();
283
	checkLastRow();
284
}
285

    
286
function checkLastRow() {
287
	if($('.repeatable').length <= 1) {
288
		$('#deleterow0').hide();
289
	} else {
290
		$('[id^=deleterow]').show();
291
	}
292
}
293

    
294
function add_row() {
295
	// Find the last repeatable group
296
	var lastRepeatableGroup = $('.repeatable:last');
297

    
298
	// Clone it
299
	var newGroup = lastRepeatableGroup.clone(true);
300

    
301
	// Increment the suffix number for each input element in the new group
302
	$(newGroup).find('input').each(function() {
303
		$(this).prop("id", bumpStringInt(this.id));
304
		$(this).prop("name", bumpStringInt(this.name));
305
		if(!$(this).is('[id^=delete]'))
306
			$(this).val('');
307
	});
308

    
309
	// Do the same for selectors
310
	$(newGroup).find('select').each(function() {
311
		$(this).prop("id", bumpStringInt(this.id));
312
		$(this).prop("name", bumpStringInt(this.name));
313
		// If this selector lists mask bits, we need it to be reset to all 128 options
314
		// and no items selected, so that automatic v4/v6 selection still works
315
		if($(this).is('[id^=address_subnet]')) {
316
			$(this).empty();
317
			for(idx=128; idx>0; idx--) {
318
				$(this).append($('<option>', {
319
					value: idx,
320
					text: idx
321
				}));
322
			}
323
		}
324
	});
325

    
326
	// And for "for" tags
327
	$(newGroup).find('label').attr('for', bumpStringInt($(newGroup).find('label').attr('for')));
328
	$(newGroup).find('label').text(""); // Clear the label. We only want it on the very first row
329

    
330
	// Insert the updated/cloned row
331
	$(lastRepeatableGroup).after(newGroup);
332

    
333
	// Delete any help text from the group we have cloned
334
	$(lastRepeatableGroup).find('.help-block').each(function() {
335
		if((typeof retainhelp) == "undefined")
336
			$(this).remove();
337
	});
338

    
339
	setMasks();
340

    
341
	checkLastRow();
342

    
343
	$('[id^=address]').autocomplete({
344
		source: addressarray
345
	});
346
}
347

    
348
// These are action buttons, not submit buttons
349
$('[id^=addrow]').prop('type','button');
350
$('[id^=delete]').prop('type','button');
351

    
352
// on click . .
353
$('[id^=addrow]').click(function() {
354
	add_row();
355
});
356

    
357
$('[id^=delete]').click(function(event) {
358
	if($('.repeatable').length > 1) {
359
		if((typeof retainhelp) == "undefined")
360
			moveHelpText(event.target.id);
361

    
362
		delete_row(event.target.id);
363
	}
364
	else
365
		alert('You may not delete the last row!');
366
});
(4-4/4)