mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
ui: Replace use of jQuery with plain JavaScript
sunil: - Add explicit dependency on libjs-jquery in janus even though another dependency brings it in. - Fix looking for elements before DOMContentLoaded is fired. Since most of the scripts are added at the end of the page, it might work now, but doing this properly after DOMContentLoaded allows us to relocate the scripts to the header of the page and add 'defer' attribute on them. - Fix issue with IPv6 method getting selected as 'dchp' in networks.js. - Don't focus on the first element in the form after the page loads. This is bad for accessibility. - Fix issue with setting the readonly/required states of IPv4/IPv6 fields on page load. - Password fields can now be changed to text fields and vice versa without a problem. Simplify. - Fix incorrect repetition of code setting 'show' class in onInvalidEvent(). - Prefer exception getting raised instead of functionality silently failing when expected elements are not found. - Use 'const' instead of 'var' wherever possible. - Prefer .closest() to get to ancestors instead of .parentNode; - Don't CSS transitions when showing an element, 'transition' CSS property does not work on 'display' property. Instead they have to implemented on 'height', 'opacity', etc. - Minor styling changes. Consistent casing. Use arrow styled functions. Signed-off-by: Joseph Nuthalapati <njoseph@riseup.net> Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: Sunil Mohan Adapa <sunil@medhas.org>
This commit is contained in:
parent
7ea06bd635
commit
68db1b9ee0
@ -22,58 +22,60 @@
|
||||
* in this page.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
var NOIP = 'https://<User>:<Pass>@dynupdate.no-ip.com/nic/update?' +
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const NOIP = 'https://<User>:<Pass>@dynupdate.no-ip.com/nic/update?' +
|
||||
'hostname=<Domain>';
|
||||
var FREEDNS = 'https://freedns.afraid.org/dynamic/update.php?' +
|
||||
const FREEDNS = 'https://freedns.afraid.org/dynamic/update.php?' +
|
||||
'_YOURAPIKEYHERE_';
|
||||
|
||||
$('#id_service_type').change(function() {
|
||||
set_mode();
|
||||
document.getElementById('id_service_type').addEventListener('change', () => {
|
||||
setMode();
|
||||
|
||||
var service_type = $("#id_service_type").val();
|
||||
if (service_type == "noip.com") {
|
||||
$('#id_update_url').val(NOIP);
|
||||
} else if (service_type == "freedns.afraid.org") {
|
||||
$('#id_update_url').val(FREEDNS);
|
||||
const service_type = document.getElementById('id_service_type').value;
|
||||
if (service_type === "noip.com") {
|
||||
document.getElementById('id_update_url').value = NOIP;
|
||||
} else if (service_type === "freedns.afraid.org") {
|
||||
document.getElementById('id_update_url').value = FREEDNS;
|
||||
} else { // GnuDIP and other
|
||||
$('#id_update_url').val('');
|
||||
document.getElementById('id_update_url').value = '';
|
||||
}
|
||||
});
|
||||
|
||||
$('#id_show_password').change(function() {
|
||||
if ($('#id_show_password').prop('checked')) {
|
||||
$('#id_password').prop('type', 'text');
|
||||
document.getElementById('id_show_password').addEventListener('change', () => {
|
||||
if (document.getElementById('id_show_password').checked) {
|
||||
document.getElementById('id_password').type = 'text';
|
||||
} else {
|
||||
$('#id_password').prop('type', 'password');
|
||||
document.getElementById('id_password').type = 'password';
|
||||
}
|
||||
});
|
||||
|
||||
function set_mode() {
|
||||
var service_type = $("#id_service_type").val();
|
||||
if (service_type == "gnudip") {
|
||||
set_gnudip_mode();
|
||||
function setMode() {
|
||||
const service_type = document.getElementById('id_service_type').value;
|
||||
if (service_type === "gnudip") {
|
||||
setGnudipMode();
|
||||
} else {
|
||||
set_update_url_mode();
|
||||
setUpdateUrlMode();
|
||||
}
|
||||
}
|
||||
|
||||
function set_gnudip_mode() {
|
||||
$('.form-group').show();
|
||||
$('#id_update_url').closest('.form-group').hide();
|
||||
$('#id_disable_ssl_cert_check').closest('.form-group').hide();
|
||||
$('#id_use_http_basic_auth').closest('.form-group').hide();
|
||||
$('#id_use_ipv6').closest('.form-group').hide();
|
||||
$('#id_server').closest('.form-group').show();
|
||||
function setGnudipMode() {
|
||||
document.querySelectorAll('.form-group').forEach((element) => {
|
||||
element.style.display = 'block';
|
||||
});
|
||||
document.getElementById('id_update_url').closest('.form-group').style.display = 'none';
|
||||
document.getElementById('id_disable_ssl_cert_check').closest('.form-group').style.display = 'none';
|
||||
document.getElementById('id_use_http_basic_auth').closest('.form-group').style.display = 'none';
|
||||
document.getElementById('id_use_ipv6').closest('.form-group').style.display = 'none';
|
||||
document.getElementById('id_server').closest('.form-group').style.display = 'block';
|
||||
}
|
||||
|
||||
function set_update_url_mode() {
|
||||
$('#id_update_url').closest('.form-group').show();
|
||||
$('#id_disable_ssl_cert_check').closest('.form-group').show();
|
||||
$('#id_use_http_basic_auth').closest('.form-group').show();
|
||||
$('#id_use_ipv6').closest('.form-group').show();
|
||||
$('#id_server').closest('.form-group').hide();
|
||||
function setUpdateUrlMode() {
|
||||
document.getElementById('id_update_url').closest('.form-group').style.display = 'block';
|
||||
document.getElementById('id_disable_ssl_cert_check').closest('.form-group').style.display = 'block';
|
||||
document.getElementById('id_use_http_basic_auth').closest('.form-group').style.display = 'block';
|
||||
document.getElementById('id_use_ipv6').closest('.form-group').style.display = 'block';
|
||||
document.getElementById('id_server').closest('.form-group').style.display = 'none';
|
||||
}
|
||||
|
||||
set_mode();
|
||||
})(jQuery);
|
||||
setMode();
|
||||
});
|
||||
|
||||
@ -22,14 +22,21 @@
|
||||
* in this page.
|
||||
*/
|
||||
|
||||
jQuery(function($) {
|
||||
$('#id_enable_managed_turn').change(function() {
|
||||
if($(this).prop('checked')) {
|
||||
$('#id_turn_uris').closest('.form-group').hide();
|
||||
$('#id_shared_secret').closest('.form-group').hide();
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const enableManagedTurn = document.getElementById('id_enable_managed_turn');
|
||||
const turnUrisGroup = document.getElementById('id_turn_uris').closest('.form-group');
|
||||
const sharedSecretGroup = document.getElementById('id_shared_secret').closest('.form-group');
|
||||
|
||||
function toggleVisibility() {
|
||||
if (enableManagedTurn.checked) {
|
||||
turnUrisGroup.style.display = 'none';
|
||||
sharedSecretGroup.style.display = 'none';
|
||||
} else {
|
||||
$('#id_turn_uris').closest('.form-group').show();
|
||||
$('#id_shared_secret').closest('.form-group').show();
|
||||
turnUrisGroup.style.display = '';
|
||||
sharedSecretGroup.style.display = '';
|
||||
}
|
||||
}).change();
|
||||
}
|
||||
|
||||
enableManagedTurn.addEventListener('change', toggleVisibility);
|
||||
toggleVisibility();
|
||||
});
|
||||
|
||||
@ -59,9 +59,9 @@ class JanusApp(app_module.App):
|
||||
self.add(shortcut)
|
||||
|
||||
packages = Packages('packages-janus', [
|
||||
'janus', 'libjs-bootbox', 'libjs-bootstrap', 'libjs-bootswatch',
|
||||
'libjs-janus-gateway', 'libjs-jquery-blockui', 'libjs-spin.js',
|
||||
'libjs-toastr', 'libjs-webrtc-adapter'
|
||||
'janus', 'libjs-jquery', 'libjs-bootbox', 'libjs-bootstrap',
|
||||
'libjs-bootswatch', 'libjs-janus-gateway', 'libjs-jquery-blockui',
|
||||
'libjs-spin.js', 'libjs-toastr', 'libjs-webrtc-adapter'
|
||||
])
|
||||
self.add(packages)
|
||||
|
||||
|
||||
@ -22,14 +22,21 @@
|
||||
* in this page.
|
||||
*/
|
||||
|
||||
jQuery(function($) {
|
||||
$('#id_enable_managed_turn').change(function() {
|
||||
if($(this).prop('checked')) {
|
||||
$('#id_turn_uris').closest('.form-group').hide();
|
||||
$('#id_shared_secret').closest('.form-group').hide();
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const enableManagedTurnCheckbox = document.getElementById('id_enable_managed_turn');
|
||||
const turnUrisFormGroup = document.getElementById('id_turn_uris').closest('.form-group');
|
||||
const sharedSecretFormGroup = document.getElementById('id_shared_secret').closest('.form-group');
|
||||
|
||||
function toggleFormGroups() {
|
||||
if (enableManagedTurnCheckbox.checked) {
|
||||
turnUrisFormGroup.style.display = 'none';
|
||||
sharedSecretFormGroup.style.display = 'none';
|
||||
} else {
|
||||
$('#id_turn_uris').closest('.form-group').show();
|
||||
$('#id_shared_secret').closest('.form-group').show();
|
||||
turnUrisFormGroup.style.display = '';
|
||||
sharedSecretFormGroup.style.display = '';
|
||||
}
|
||||
}).change();
|
||||
}
|
||||
|
||||
enableManagedTurnCheckbox.addEventListener('change', toggleFormGroups);
|
||||
toggleFormGroups();
|
||||
});
|
||||
|
||||
@ -22,18 +22,19 @@
|
||||
* in this page.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$('#id_enable_public_registrations').click(function() {
|
||||
var checkedState = $(this).prop("checked");
|
||||
if (checkedState) {
|
||||
$('#id_enable_private_mode').prop('checked', false);
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const enablePublicRegistrations = document.getElementById('id_enable_public_registrations');
|
||||
const enablePrivateMode = document.getElementById('id_enable_private_mode');
|
||||
|
||||
enablePublicRegistrations.addEventListener('click', () => {
|
||||
if (enablePublicRegistrations.checked) {
|
||||
enablePrivateMode.checked = false;
|
||||
}
|
||||
});
|
||||
|
||||
$('#id_enable_private_mode').click(function() {
|
||||
var checkedState = $(this).prop("checked");
|
||||
if (checkedState) {
|
||||
$('#id_enable_public_registrations').prop('checked', false);
|
||||
enablePrivateMode.addEventListener('click', () => {
|
||||
if (enablePrivateMode.checked) {
|
||||
enablePublicRegistrations.checked = false;
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
});
|
||||
|
||||
@ -22,81 +22,94 @@
|
||||
* in this page.
|
||||
*/
|
||||
|
||||
jQuery(function($) {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
function ip_required(required, ip_version, fields) {
|
||||
var prefix = '#id_' + ip_version + '_';
|
||||
function ipRequired(required, ipVersion, fields) {
|
||||
const prefix = 'id_' + ipVersion + '_';
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
$(prefix + fields[i]).prop("required", required);
|
||||
}
|
||||
}
|
||||
|
||||
function ip_readonly(readonly, ip_version, fields) {
|
||||
var prefix = '#id_' + ip_version + '_';
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
$(prefix + fields[i]).prop("readOnly", readonly);
|
||||
if (readonly) {
|
||||
$(prefix + fields[i]).val("");
|
||||
$(prefix + fields[i]).prop("required", false);
|
||||
const element = document.getElementById(prefix + fields[i]);
|
||||
if (element) {
|
||||
element.required = required;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function on_ipv4_method_change() {
|
||||
var selected = $("input[name=ipv4_method]:checked");
|
||||
if (selected.prop("value") == "manual") {
|
||||
ip_required(true, 'ipv4', ['address']);
|
||||
ip_readonly(false, 'ipv4', ['address', 'netmask', 'gateway',
|
||||
function ipReadOnly(readOnly, ipVersion, fields) {
|
||||
const prefix = 'id_' + ipVersion + '_';
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
const element = document.getElementById(prefix + fields[i]);
|
||||
if (element) {
|
||||
element.readOnly = readOnly;
|
||||
if (readOnly) {
|
||||
element.value = "";
|
||||
element.required = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onIpv4MethodChange() {
|
||||
const selected = document.querySelector("input[name=ipv4_method]:checked");
|
||||
if (selected && selected.value === "manual") {
|
||||
ipRequired(true, 'ipv4', ['address']);
|
||||
ipReadOnly(false, 'ipv4', ['address', 'netmask', 'gateway',
|
||||
'dns', 'second_dns'
|
||||
]);
|
||||
} else if (selected.prop("value") == "shared") {
|
||||
ip_required(false, 'ipv4', ['address']);
|
||||
ip_readonly(false, 'ipv4', ['address', 'netmask']);
|
||||
ip_readonly(true, 'ipv4', ['gateway', 'dns', 'second_dns']);
|
||||
} else if (selected.prop("value") == "auto") {
|
||||
ip_readonly(true, 'ipv4', ['address', 'netmask', 'gateway']);
|
||||
ip_readonly(false, 'ipv4', ['dns', 'second_dns']);
|
||||
} else if (selected && selected.value === "shared") {
|
||||
ipRequired(false, 'ipv4', ['address']);
|
||||
ipReadOnly(false, 'ipv4', ['address', 'netmask']);
|
||||
ipReadOnly(true, 'ipv4', ['gateway', 'dns', 'second_dns']);
|
||||
} else if (selected && selected.value === "auto") {
|
||||
ipReadOnly(true, 'ipv4', ['address', 'netmask', 'gateway']);
|
||||
ipReadOnly(false, 'ipv4', ['dns', 'second_dns']);
|
||||
} else {
|
||||
ip_readonly(true, 'ipv4', ['address', 'netmask', 'gateway',
|
||||
ipReadOnly(true, 'ipv4', ['address', 'netmask', 'gateway',
|
||||
'dns', 'second_dns'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function on_ipv6_method_change() {
|
||||
var selected = $("input[name=ipv6_method]:checked");
|
||||
if (selected.prop("value") == "manual") {
|
||||
ip_required(true, 'ipv6', ['address', 'prefix']);
|
||||
ip_readonly(false, 'ipv6', ['address', 'prefix', 'gateway',
|
||||
function onIpv6MethodChange() {
|
||||
const selected = document.querySelector("input[name=ipv6_method]:checked");
|
||||
if (selected && selected.value === "manual") {
|
||||
ipRequired(true, 'ipv6', ['address', 'prefix']);
|
||||
ipReadOnly(false, 'ipv6', ['address', 'prefix', 'gateway',
|
||||
'dns', 'second_dns'
|
||||
]);
|
||||
} else if (selected.prop("value") == "auto" ||
|
||||
$("#id_ipv6_method").prop("value") == "dhcp") {
|
||||
ip_readonly(true, 'ipv6', ['address', 'prefix', 'gateway']);
|
||||
ip_readonly(false, 'ipv6', ['dns', 'second_dns']);
|
||||
} else if (selected && (selected.value === "auto" ||
|
||||
selected.value === "dhcp")) {
|
||||
ipReadOnly(true, 'ipv6', ['address', 'prefix', 'gateway']);
|
||||
ipReadOnly(false, 'ipv6', ['dns', 'second_dns']);
|
||||
} else {
|
||||
ip_readonly(true, 'ipv6', ['address', 'prefix', 'gateway',
|
||||
ipReadOnly(true, 'ipv6', ['address', 'prefix', 'gateway',
|
||||
'dns', 'second_dns'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$("#id_name").focus();
|
||||
|
||||
$("input[name=ipv4_method]").change(on_ipv4_method_change).change();
|
||||
$("input[name=ipv6_method]").change(on_ipv6_method_change).change();
|
||||
|
||||
$('#id_show_password').change(function() {
|
||||
// Changing type attribute from password to text is prevented by
|
||||
// most browsers. Making a new form field works.
|
||||
new_type = 'password';
|
||||
if ($('#id_show_password').prop('checked'))
|
||||
new_type = 'text';
|
||||
|
||||
$('#id_password').replaceWith(
|
||||
$('#id_password').clone().attr('type', new_type));
|
||||
document.querySelectorAll("input[name=ipv4_method]").forEach(element => {
|
||||
element.addEventListener('change', onIpv4MethodChange);
|
||||
});
|
||||
|
||||
document.querySelectorAll("input[name=ipv6_method]").forEach(element => {
|
||||
element.addEventListener('change', onIpv6MethodChange);
|
||||
});
|
||||
|
||||
onIpv4MethodChange();
|
||||
onIpv6MethodChange();
|
||||
|
||||
const showPasswordElement = document.getElementById('id_show_password');
|
||||
if (showPasswordElement) {
|
||||
showPasswordElement.addEventListener('change', () => {
|
||||
// Changing type attribute from password to text is prevented by
|
||||
// most browsers. Making a new form field works.
|
||||
var newType = 'password';
|
||||
if (showPasswordElement.checked) {
|
||||
newType = 'text';
|
||||
}
|
||||
document.getElementById('id_password').type = newType;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// When there are validation errors on form elements, expand their parent
|
||||
@ -104,14 +117,14 @@ jQuery(function($) {
|
||||
// can be show by the browser.
|
||||
document.addEventListener('DOMContentLoaded', event => {
|
||||
const selector = '.form-connection input, .form-connection select';
|
||||
const input_elements = document.querySelectorAll(selector);
|
||||
input_elements.forEach(input =>
|
||||
input.addEventListener('invalid', on_invalid_event)
|
||||
const inputElements = document.querySelectorAll(selector);
|
||||
inputElements.forEach(input =>
|
||||
input.addEventListener('invalid', onInvalidEvent)
|
||||
);
|
||||
});
|
||||
|
||||
function on_invalid_event(event) {
|
||||
const element = event.target;
|
||||
function onInvalidEvent(event) {
|
||||
const element = event.currentTarget;
|
||||
const parent = element.closest('.collapse');
|
||||
// Don't use .collapse(). Instead, expand all the sections with errors.
|
||||
parent.classList.add('show');
|
||||
|
||||
@ -22,12 +22,15 @@
|
||||
* in this page.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$("#select-all").click(function() {
|
||||
var checkedState = this.checked;
|
||||
checkboxes = document.getElementsByName('snapshot_list');
|
||||
jQuery.each(checkboxes, function(i, checkbox) {
|
||||
checkbox.checked = checkedState;
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const selectAllCheckbox = document.getElementById('select-all');
|
||||
if (selectAllCheckbox) {
|
||||
selectAllCheckbox.addEventListener('click', (event) => {
|
||||
const checkedState = event.currentTarget.checked;
|
||||
const checkboxes = document.getElementsByName('snapshot_list');
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.checked = checkedState;
|
||||
});
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
}
|
||||
});
|
||||
|
||||
@ -22,26 +22,38 @@
|
||||
* in this page.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$('#id_tor-relay_enabled').change(function() {
|
||||
var bridge = $('#id_tor-bridge_relay_enabled');
|
||||
var disable = !$('#id_tor-relay_enabled').prop('checked');
|
||||
bridge.prop('disabled', disable);
|
||||
if (disable) {
|
||||
$('#id_tor-bridge_relay_enabled').prop('checked', false);
|
||||
}
|
||||
}).change();
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const relayEnabled = document.getElementById('id_tor-relay_enabled');
|
||||
const bridgeRelay = document.getElementById('id_tor-bridge_relay_enabled');
|
||||
const useUpstreamBridges = document.getElementById('id_tor-use_upstream_bridges');
|
||||
const upstreamBridgesField = document.getElementById('id_tor-upstream_bridges')
|
||||
.closest('.form-group');
|
||||
|
||||
$('#id_tor-use_upstream_bridges').change(function() {
|
||||
if ($('#id_tor-use_upstream_bridges').prop('checked')) {
|
||||
$('#id_tor-upstream_bridges').parent().parent().show('slow');
|
||||
$('#id_tor-relay_enabled').prop('checked', false)
|
||||
.prop('disabled', true);
|
||||
$('#id_tor-bridge_relay_enabled').prop('checked', false)
|
||||
.prop('disabled', true);
|
||||
} else {
|
||||
$('#id_tor-upstream_bridges').parent().parent().hide('slow');
|
||||
$('#id_tor-relay_enabled').prop('disabled', false);
|
||||
function handleRelayChange() {
|
||||
const disable = !relayEnabled.checked;
|
||||
bridgeRelay.disabled = disable;
|
||||
if (disable) {
|
||||
bridgeRelay.checked = false;
|
||||
}
|
||||
}).change();
|
||||
})(jQuery);
|
||||
}
|
||||
|
||||
function handleUseUpstreamBridgesChange() {
|
||||
if (useUpstreamBridges.checked) {
|
||||
upstreamBridgesField.style.display = '';
|
||||
relayEnabled.checked = false;
|
||||
relayEnabled.disabled = true;
|
||||
bridgeRelay.checked = false;
|
||||
bridgeRelay.disabled = true;
|
||||
} else {
|
||||
upstreamBridgesField.style.display = 'none';
|
||||
relayEnabled.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
relayEnabled.addEventListener('change', handleRelayChange);
|
||||
useUpstreamBridges.addEventListener('change', handleUseUpstreamBridgesChange);
|
||||
|
||||
// Initial state
|
||||
handleRelayChange();
|
||||
handleUseUpstreamBridgesChange();
|
||||
});
|
||||
|
||||
@ -22,12 +22,20 @@
|
||||
* in this page.
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
$('#id_torproxy-use_upstream_bridges').change(function() {
|
||||
if ($('#id_torproxy-use_upstream_bridges').prop('checked')) {
|
||||
$('#id_torproxy-upstream_bridges').parent().parent().show('slow');
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const useUpstreamBridges = document.getElementById('id_torproxy-use_upstream_bridges');
|
||||
const upstreamBridges = document.getElementById('id_torproxy-upstream_bridges');
|
||||
|
||||
function handleUseUpstreamBridgesChange() {
|
||||
if (useUpstreamBridges.checked) {
|
||||
upstreamBridges.closest('.form-group').style.display = '';
|
||||
} else {
|
||||
$('#id_torproxy-upstream_bridges').parent().parent().hide('slow');
|
||||
upstreamBridges.closest('.form-group').style.display = 'none';
|
||||
}
|
||||
}).change();
|
||||
})(jQuery);
|
||||
}
|
||||
|
||||
useUpstreamBridges.addEventListener('change', handleUseUpstreamBridgesChange);
|
||||
|
||||
// Initial state
|
||||
handleUseUpstreamBridgesChange();
|
||||
});
|
||||
|
||||
@ -58,9 +58,6 @@
|
||||
<link rel="stylesheet" href="{% static user_css %}"/>
|
||||
{% endif %}
|
||||
|
||||
<!-- Local link to system jQuery -->
|
||||
<!-- TODO Deferring jQuery is causing scripts to be loaded before jQuery is available -->
|
||||
<script type="text/javascript" src="{% static '/javascript/jquery/jquery.min.js' %}"></script>
|
||||
<!-- Local link to system Bootstrap JS -->
|
||||
<script type="text/javascript" src="{% static '/javascript/popper.js/umd/popper.js' %}" defer></script>
|
||||
<script type="text/javascript" src="{% static 'theme/js/fix.js' %}" defer></script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user