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
|
// Eat all of the options with a value greater than max. We don't want them to be available
|
161
|
while (select.options[0].value > max)
|
162
|
select.remove(0);
|
163
|
|
164
|
if (select.options.length < max) {
|
165
|
for (var i=select.options.length; i<=max; i++)
|
166
|
select.options.add(new Option(i, i), 0);
|
167
|
}
|
168
|
});
|
169
|
|
170
|
// Fire immediately
|
171
|
input.change();
|
172
|
});
|
173
|
|
174
|
// Add confirm to all btn-danger buttons and fa-trash icons
|
175
|
// Use element title in the confirmation message, or if not available
|
176
|
// the element value
|
177
|
$('.btn-danger, .fa-trash').on('click', function(e){
|
178
|
if (!($(this).hasClass('no-confirm'))) {
|
179
|
var msg = $.trim(this.textContent);
|
180
|
|
181
|
if (!msg)
|
182
|
var msg = $.trim(this.value).toLowerCase();
|
183
|
|
184
|
var q = 'Are you sure you wish to '+ msg +'?';
|
185
|
|
186
|
if ($(this).attr('title') != undefined)
|
187
|
q = 'Are you sure you wish to '+ $(this).attr('title').toLowerCase() + '?';
|
188
|
|
189
|
if (!confirm(q)) {
|
190
|
e.preventDefault();
|
191
|
e.stopPropagation(); // Don't leave ancestor(s) selected.
|
192
|
}
|
193
|
}
|
194
|
});
|
195
|
|
196
|
// Add toggle-all when there are multiple checkboxes
|
197
|
$('.control-label + .checkbox.multi').each(function() {
|
198
|
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>');
|
199
|
|
200
|
a.on('click', function() {
|
201
|
var wrap = $(this).parents('.form-group').find('.checkbox.multi'),
|
202
|
all = wrap.find('input[type=checkbox]'),
|
203
|
checked = wrap.find('input[type=checkbox]:checked');
|
204
|
|
205
|
all.prop('checked', (all.length != checked.length));
|
206
|
});
|
207
|
|
208
|
a.appendTo($(this));
|
209
|
});
|
210
|
|
211
|
// The need to NOT hide the advanced options if the elements therein are not set to the system
|
212
|
// default values makes it better to handle advanced option hiding in each PHP file so this is being
|
213
|
// disabled for now by changing the class name it acts on to "auto-advanced"
|
214
|
|
215
|
// Hide advanced inputs by default
|
216
|
if ($('.auto-advanced').length > 0)
|
217
|
{
|
218
|
var advButt = $('<a id="toggle-advanced" class="btn btn-default">toggle advanced options</a>');
|
219
|
advButt.on('click', function() {
|
220
|
$('.advanced').parents('.form-group').collapse('toggle');
|
221
|
});
|
222
|
|
223
|
advButt.insertAfter($('#save'));
|
224
|
|
225
|
$('.auto-advanced').parents('.form-group').collapse({toggle: true});
|
226
|
}
|
227
|
|
228
|
var originalLeave = $.fn.popover.Constructor.prototype.leave;
|
229
|
$.fn.popover.Constructor.prototype.leave = function(obj){
|
230
|
var self = obj instanceof this.constructor ?
|
231
|
obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
|
232
|
var container, timeout;
|
233
|
|
234
|
originalLeave.call(this, obj);
|
235
|
|
236
|
if (self.$tip && self.$tip.length) {
|
237
|
container = self.$tip;
|
238
|
timeout = self.timeout;
|
239
|
container.one('mouseenter', function(){
|
240
|
//We entered the actual popover - call off the dogs
|
241
|
clearTimeout(timeout);
|
242
|
//Let's monitor popover content instead
|
243
|
container.one('mouseleave', function(){
|
244
|
$.fn.popover.Constructor.prototype.leave.call(self, self);
|
245
|
});
|
246
|
})
|
247
|
}
|
248
|
};
|
249
|
|
250
|
// Enable popovers globally
|
251
|
$('[data-toggle="popover"]').popover({ delay: {show: 50, hide: 400} });
|
252
|
|
253
|
// Force correct initial state for toggleable checkboxes
|
254
|
$('input[type=checkbox][data-toggle="collapse"]:not(:checked)').each(function() {
|
255
|
$( $(this).data('target') ).addClass('collapse');
|
256
|
});
|
257
|
|
258
|
$('input[type=checkbox][data-toggle="disable"]:not(:checked)').each(function() {
|
259
|
$( $(this).data('target') ).prop('disabled', true);
|
260
|
});
|
261
|
|
262
|
$('.table-rowdblclickedit>tbody>tr').dblclick(function () {
|
263
|
$(this).find(".fa-pencil")[0].click();
|
264
|
});
|
265
|
|
266
|
// Focus first input
|
267
|
$(':input:enabled:visible:first').focus();
|
268
|
|
269
|
$(".resizable").each(function() {
|
270
|
$(this).css('height', 80).resizable({minHeight: 80, minWidth: 200}).parent().css('padding-bottom', 0);
|
271
|
$(this).css('height', 78);
|
272
|
});
|
273
|
|
274
|
// Run in-page defined events
|
275
|
while (func = window.events.shift())
|
276
|
func();
|
277
|
});
|
278
|
|
279
|
// Implement data-toggle=disable
|
280
|
// Source: https://github.com/synergic-cz/synergic-ui/blob/master/src/js/disable.js
|
281
|
;(function($, window, document) {
|
282
|
'use strict';
|
283
|
|
284
|
var Disable = function($element) {
|
285
|
this.$element = $element;
|
286
|
};
|
287
|
|
288
|
Disable.prototype.toggle = function() {
|
289
|
this.$element.prop('disabled', !this.$element.prop('disabled'));
|
290
|
};
|
291
|
|
292
|
function Plugin(options) {
|
293
|
$(document).trigger('toggle.sui.disable');
|
294
|
|
295
|
this.each(function() {
|
296
|
var $this = $(this);
|
297
|
var data = $this.data('sui.disable');
|
298
|
|
299
|
if (!data) {
|
300
|
$this.data('sui.disable', (data = new Disable($this)));
|
301
|
}
|
302
|
|
303
|
if (options === 'toggle') {
|
304
|
data.toggle();
|
305
|
}
|
306
|
});
|
307
|
|
308
|
$(document).trigger('toggled.sui.disable');
|
309
|
|
310
|
return this;
|
311
|
}
|
312
|
|
313
|
var old = $.fn.disable;
|
314
|
|
315
|
$.fn.disable = Plugin;
|
316
|
$.fn.disable.Constructor = Disable;
|
317
|
|
318
|
$.fn.disable.noConflict = function() {
|
319
|
$.fn.disable = old;
|
320
|
return this;
|
321
|
};
|
322
|
|
323
|
(function(Plugin, $, window) {
|
324
|
$(window).load(function() {
|
325
|
var $controls = $('[data-toggle=disable]');
|
326
|
|
327
|
$controls.each(function() {
|
328
|
var $this = $(this);
|
329
|
var eventType = $this.data('disable-event');
|
330
|
if (!eventType) {
|
331
|
eventType = 'change';
|
332
|
}
|
333
|
$this.on(eventType + '.sui.disable.data-api', function() {
|
334
|
Plugin.call($($this.data('target')), 'toggle');
|
335
|
});
|
336
|
});
|
337
|
});
|
338
|
}(Plugin, $, window, document));
|
339
|
}(jQuery, window, document));
|