Project

General

Profile

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

    
53
/*
54
 * This file should only contain functions that will be used on more than 2 pages
55
 */
56

    
57
$(function() {
58
	// Attach collapsable behaviour to select options
59
	(function()
60
	{
61
		var selects = $('select[data-toggle="collapse"]');
62

    
63
		selects.on('change', function(){
64
			var options = $(this).find('option');
65
			var selectedValue = $(this).find(':selected').val();
66

    
67
			options.each(function(){
68
				if ($(this).val() == selectedValue)
69
					return;
70

    
71
				targets = $('.toggle-'+ $(this).val() +'.in:not(.toggle-'+ selectedValue +')');
72

    
73
				// Hide related collapsables which are visible (.in)
74
				targets.collapse('hide');
75

    
76
				// Disable all invisible inputs
77
				targets.find(':input').prop('disabled', true);
78
			});
79

    
80
			$('.toggle-' + selectedValue).collapse('show').find(':input').prop('disabled', false);
81
		});
82

    
83
		// Trigger change to open currently selected item
84
		selects.trigger('change');
85
	})();
86

    
87

    
88
	// Add +/- buttons to certain Groups; to allow adding multiple entries
89
	// This time making the buttons col-2 wide so they can fit on the same line as the
90
	// rest of the group (providing the total width of the group is col-8 or less)
91
	(function()
92
	{
93
		var groups = $('div.form-group.user-duplication-horiz');
94
		var controlsContainer = $('<div class="col-sm-2"></div>');
95
		var plus = $('<a class="btn btn-sm btn-success"><i class="fa fa-plus icon-embed-btn"></i>Add</a>');
96
		var minus = $('<a class="btn btn-sm btn-warning"><i class="fa fa-trash icon-embed-btn"></i>Delete</a>');
97

    
98
		minus.on('click', function(){
99
			$(this).parents('div.form-group').remove();
100
		});
101

    
102
		plus.on('click', function(){
103
			var group = $(this).parents('div.form-group');
104

    
105
			var clone = group.clone(true);
106
			clone.find('*').val('');
107
			clone.appendTo(group.parent());
108
		});
109

    
110
		groups.each(function(idx, group){
111
			var controlsClone = controlsContainer.clone(true).appendTo(group);
112
			minus.clone(true).appendTo(controlsClone);
113

    
114
			if (group == group.parentNode.lastElementChild)
115
				plus.clone(true).appendTo(controlsClone);
116
		});
117
	})();
118

    
119
	// Add +/- buttons to certain Groups; to allow adding multiple entries
120
	(function()
121
	{
122
		var groups = $('div.form-group.user-duplication');
123
		var controlsContainer = $('<div class="col-sm-10 col-sm-offset-2 controls"></div>');
124
		var plus = $('<a class="btn btn-xs btn-success"><i class="fa fa-plus icon-embed-btn"></i>Add</a>');
125
		var minus = $('<a class="btn btn-xs btn-warning"><i class="fa fa-trash icon-embed-btn"></i>Delete</a>');
126

    
127
		minus.on('click', function(){
128
			$(this).parents('div.form-group').remove();
129
		});
130

    
131
		plus.on('click', function(){
132
			var group = $(this).parents('div.form-group');
133

    
134
			var clone = group.clone(true);
135
			clone.find('*').removeAttr('value');
136
			clone.appendTo(group.parent());
137
		});
138

    
139
		groups.each(function(idx, group){
140
			var controlsClone = controlsContainer.clone(true).appendTo(group);
141
			minus.clone(true).appendTo(controlsClone);
142

    
143
			if (group == group.parentNode.lastElementChild)
144
				plus.clone(true).appendTo(controlsClone);
145
		});
146
	})();
147

    
148
	// Automatically change IpAddress mask selectors to 128/32 options for IPv6/IPv4 addresses
149
	$('span.pfIpMask + select').each(function (idx, select){
150
		var input = $(select).prevAll('input[type=text]');
151

    
152
		input.on('change', function(e){
153
			var isV6 = (input.val().indexOf(':') != -1), min = 0, max = 128;
154
			if (!isV6)
155
				max = 32;
156

    
157
			if (input.val() == "")
158
				return;
159

    
160
			var attr = $(select).attr('disabled');
161

    
162
			// Don't do anything if the mask selector is disabled
163
			if (typeof attr === typeof undefined || attr === false) {
164
				// Eat all of the options with a value greater than max. We don't want them to be available
165
				while (select.options[0].value > max)
166
					select.remove(0);
167

    
168
				if (select.options.length < max) {
169
					for (var i=select.options.length; i<=max; i++)
170
						select.options.add(new Option(i, i), 0);
171
					// Make sure index 0 is selected otherwise it will stay in "32" for V6
172
					select.options.selectedIndex = "0";
173
				}
174
			}
175
		});
176

    
177
		// Fire immediately
178
		input.change();
179
	});
180

    
181
	// Add confirm to all btn-danger buttons and fa-trash icons
182
	// Use element title in the confirmation message, or if not available
183
	// the element value
184
	$('.btn-danger, .fa-trash').on('click', function(e){
185
		if (!($(this).hasClass('no-confirm')) && !($(this).hasClass('icon-embed-btn'))) {
186
			var msg = $.trim(this.textContent).toLowerCase();
187

    
188
			if (!msg)
189
				var msg = $.trim(this.value).toLowerCase();
190

    
191
			var q = 'Are you sure you wish to '+ msg +'?';
192

    
193
			if ($(this).attr('title') != undefined)
194
				q = 'Are you sure you wish to '+ $(this).attr('title').toLowerCase() + '?';
195

    
196
			if (!confirm(q)) {
197
				e.preventDefault();
198
				e.stopPropagation();	// Don't leave ancestor(s) selected.
199
			}
200
		}
201
	});
202

    
203
	// Add toggle-all when there are multiple checkboxes
204
	$('.control-label + .checkbox.multi').each(function() {
205
		var a = $('<a name="btntoggleall" class="btn btn-xs btn-info"><i class="fa fa-check-square-o icon-embed-btn"></i>Toggle All</a>');
206

    
207
		a.on('click', function() {
208
			var wrap = $(this).parents('.form-group').find('.checkbox.multi'),
209
				all = wrap.find('input[type=checkbox]'),
210
				checked = wrap.find('input[type=checkbox]:checked');
211

    
212
			all.prop('checked', (all.length != checked.length));
213
		});
214

    
215
		a.appendTo($(this));
216
	});
217

    
218
	// The need to NOT hide the advanced options if the elements therein are not set to the system
219
	// default values makes it better to handle advanced option hiding in each PHP file so this is being
220
	// disabled for now by changing the class name it acts on to "auto-advanced"
221

    
222
	// Hide advanced inputs by default
223
	if ($('.auto-advanced').length > 0)
224
	{
225
		var advButt = $('<a id="toggle-advanced" class="btn btn-default">toggle advanced options</a>');
226
		advButt.on('click', function() {
227
			$('.advanced').parents('.form-group').collapse('toggle');
228
		});
229

    
230
		advButt.insertAfter($('#save'));
231

    
232
		$('.auto-advanced').parents('.form-group').collapse({toggle: true});
233
	}
234

    
235
	var originalLeave = $.fn.popover.Constructor.prototype.leave;
236
	$.fn.popover.Constructor.prototype.leave = function(obj){
237
	  var self = obj instanceof this.constructor ?
238
	    obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
239
	  var container, timeout;
240

    
241
	  originalLeave.call(this, obj);
242

    
243
	  if (self.$tip && self.$tip.length) {
244
	    container = self.$tip;
245
	    timeout = self.timeout;
246
	    container.one('mouseenter', function(){
247
	      //We entered the actual popover - call off the dogs
248
	      clearTimeout(timeout);
249
	      //Let's monitor popover content instead
250
	      container.one('mouseleave', function(){
251
	        $.fn.popover.Constructor.prototype.leave.call(self, self);
252
	      });
253
	    })
254
	  }
255
	};
256

    
257
	// Enable popovers globally
258
	$('[data-toggle="popover"]').popover({ delay: {show: 50, hide: 400} });
259

    
260
	// Force correct initial state for toggleable checkboxes
261
	$('input[type=checkbox][data-toggle="collapse"]:not(:checked)').each(function() {
262
		$( $(this).data('target') ).addClass('collapse');
263
	});
264

    
265
	$('input[type=checkbox][data-toggle="disable"]:not(:checked)').each(function() {
266
		$( $(this).data('target') ).prop('disabled', true);
267
	});
268

    
269
	$('.table-rowdblclickedit>tbody>tr').dblclick(function () {
270
		$(this).find(".fa-pencil")[0].click();
271
	});
272

    
273
	// Focus first input
274
	$(':input:enabled:visible:first').focus();
275

    
276
	$(".resizable").each(function() {
277
		$(this).css('height', 80).resizable({minHeight: 80, minWidth: 200}).parent().css('padding-bottom', 0);
278
		$(this).css('height', 78);
279
	});
280

    
281
	// Run in-page defined events
282
	while (func = window.events.shift())
283
		func();
284
});
285

    
286
// Implement data-toggle=disable
287
// Source: https://github.com/synergic-cz/synergic-ui/blob/master/src/js/disable.js
288
;(function($, window, document) {
289
	'use strict';
290

    
291
	var Disable = function($element) {
292
		this.$element = $element;
293
	};
294

    
295
	Disable.prototype.toggle = function() {
296
		this.$element.prop('disabled', !this.$element.prop('disabled'));
297
	};
298

    
299
	function Plugin(options) {
300
		$(document).trigger('toggle.sui.disable');
301

    
302
		this.each(function() {
303
			var $this = $(this);
304
			var data = $this.data('sui.disable');
305

    
306
			if (!data) {
307
				$this.data('sui.disable', (data = new Disable($this)));
308
			}
309

    
310
			if (options === 'toggle') {
311
				data.toggle();
312
			}
313
		});
314

    
315
		$(document).trigger('toggled.sui.disable');
316

    
317
		return this;
318
	}
319

    
320
	var old = $.fn.disable;
321

    
322
	$.fn.disable = Plugin;
323
	$.fn.disable.Constructor = Disable;
324

    
325
	$.fn.disable.noConflict = function() {
326
		$.fn.disable = old;
327
		return this;
328
	};
329

    
330
	(function(Plugin, $, window) {
331
		$(window).load(function() {
332
			var $controls = $('[data-toggle=disable]');
333

    
334
			$controls.each(function() {
335
				var $this = $(this);
336
				var eventType = $this.data('disable-event');
337
				if (!eventType) {
338
					eventType = 'change';
339
				}
340
				$this.on(eventType + '.sui.disable.data-api', function() {
341
					Plugin.call($($this.data('target')), 'toggle');
342
				});
343
			});
344
		});
345
	}(Plugin, $, window, document));
346
}(jQuery, window, document));
(1-1/4)