| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- $(document).ready(function() {
- // Pagination
- $('select#per_page').change(function() {
- this.form.submit();
- });
- // "Toggle" checkbox for object lists (PK column)
- $('input:checkbox.toggle').click(function() {
- $(this).closest('table').find('input:checkbox[name=pk]:visible').prop('checked', $(this).prop('checked'));
- // Show the "select all" box if present
- if ($(this).is(':checked')) {
- $('#select_all_box').removeClass('hidden');
- } else {
- $('#select_all').prop('checked', false);
- }
- });
- // Uncheck the "toggle" and "select all" checkboxes if an item is unchecked
- $('input:checkbox[name=pk]').click(function (event) {
- if (!$(this).attr('checked')) {
- $('input:checkbox.toggle, #select_all').prop('checked', false);
- }
- });
- // Enable hidden buttons when "select all" is checked
- $('#select_all').click(function() {
- if ($(this).is(':checked')) {
- $('#select_all_box').find('button').prop('disabled', '');
- } else {
- $('#select_all_box').find('button').prop('disabled', 'disabled');
- }
- });
- // Slugify
- function slugify(s, num_chars) {
- s = s.replace(/[^\-\.\w\s]/g, ''); // Remove unneeded chars
- s = s.replace(/^[\s\.]+|[\s\.]+$/g, ''); // Trim leading/trailing spaces
- s = s.replace(/[\-\.\s]+/g, '-'); // Convert spaces and decimals to hyphens
- s = s.toLowerCase(); // Convert to lowercase
- return s.substring(0, num_chars); // Trim to first num_chars chars
- }
- var slug_field = $('#id_slug');
- slug_field.change(function() {
- $(this).attr('_changed', true);
- });
- if (slug_field) {
- var slug_source = $('#id_' + slug_field.attr('slug-source'));
- var slug_length = slug_field.attr('maxlength');
- slug_source.on('keyup change', function() {
- if (slug_field && !slug_field.attr('_changed')) {
- slug_field.val(slugify($(this).val(), (slug_length ? slug_length : 50)));
- }
- })
- }
- // Bulk edit nullification
- $('input:checkbox[name=_nullify]').click(function() {
- $('#id_' + this.value).toggle('disabled');
- });
- // Set formaction and submit using a link
- $('a.formaction').click(function(event) {
- event.preventDefault();
- var form = $(this).closest('form');
- form.attr('action', $(this).attr('href'));
- form.submit();
- });
- // Parse URLs which may contain variable refrences to other field values
- function parseURL(url) {
- var filter_regex = /\{\{([a-z_]+)\}\}/g;
- var match;
- var rendered_url = url;
- var filter_field;
- while (match = filter_regex.exec(url)) {
- filter_field = $('#id_' + match[1]);
- var custom_attr = $('option:selected', filter_field).attr('api-value');
- if (custom_attr) {
- rendered_url = rendered_url.replace(match[0], custom_attr);
- } else if (filter_field.val()) {
- rendered_url = rendered_url.replace(match[0], filter_field.val());
- } else if (filter_field.attr('nullable') == 'true') {
- rendered_url = rendered_url.replace(match[0], 'null');
- }
- }
- return rendered_url
- }
- // Assign color picker selection classes
- function colorPickerClassCopy(data, container) {
- if (data.element) {
- // Swap the style
- $(container).attr('style', $(data.element).attr("style"));
- }
- return data.text;
- }
- // Color Picker
- $('.netbox-select2-color-picker').select2({
- allowClear: true,
- placeholder: "---------",
- theme: "bootstrap",
- templateResult: colorPickerClassCopy,
- templateSelection: colorPickerClassCopy,
- width: "off"
- });
- // Static choice selection
- $('.netbox-select2-static').select2({
- allowClear: true,
- placeholder: "---------",
- theme: "bootstrap",
- width: "off"
- });
- // API backed selection
- // Includes live search and chained fields
- // The `multiple` setting may be controled via a data-* attribute
- $('.netbox-select2-api').select2({
- allowClear: true,
- placeholder: "---------",
- theme: "bootstrap",
- width: "off",
- ajax: {
- delay: 500,
- url: function(params) {
- var element = this[0];
- var url = parseURL(element.getAttribute("data-url"));
- if (url.includes("{{")) {
- // URL is not fully rendered yet, abort the request
- return false;
- }
- return url;
- },
- data: function(params) {
- var element = this[0];
- // Paging. Note that `params.page` indexes at 1
- var offset = (params.page - 1) * 50 || 0;
- // Base query params
- var parameters = {
- q: params.term,
- limit: 50,
- offset: offset,
- };
- // Allow for controlling the brief setting from within APISelect
- parameters.brief = ( $(element).is('[data-full]') ? undefined : true );
- // filter-for fields from a chain
- var attr_name = "data-filter-for-" + $(element).attr("name");
- var form = $(element).closest('form');
- var filter_for_elements = form.find("select[" + attr_name + "]");
- filter_for_elements.each(function(index, filter_for_element) {
- var param_name = $(filter_for_element).attr(attr_name);
- var is_nullable = $(filter_for_element).attr("nullable");
- var is_visible = $(filter_for_element).is(":visible");
- var value = $(filter_for_element).val();
- if (param_name && is_visible && value) {
- parameters[param_name] = value;
- } else if (param_name && is_visible && is_nullable) {
- parameters[param_name] = "null";
- }
- });
- // Conditional query params
- $.each(element.attributes, function(index, attr){
- if (attr.name.includes("data-conditional-query-param-")){
- var conditional = attr.name.split("data-conditional-query-param-")[1].split("__");
- var field = $("#id_" + conditional[0]);
- var field_value = conditional[1];
- if ($('option:selected', field).attr('api-value') === field_value){
- var _val = attr.value.split("=");
- parameters[_val[0]] = _val[1];
- }
- }
- });
- // Additional query params
- $.each(element.attributes, function(index, attr){
- if (attr.name.includes("data-additional-query-param-")){
- var param_name = attr.name.split("data-additional-query-param-")[1];
- if (param_name in parameters) {
- if (Array.isArray(parameters[param_name])) {
- parameters[param_name].push(attr.value)
- } else {
- parameters[param_name] = [parameters[param_name], attr.value]
- }
- } else {
- parameters[param_name] = attr.value;
- }
- }
- });
- // This will handle params with multiple values (i.e. for list filter forms)
- return $.param(parameters, true);
- },
- processResults: function (data) {
- var element = this.$element[0];
- $(element).children('option').attr('disabled', false);
- var results = data.results;
- results = results.reduce((results,record,idx) => {
- record.text = record[element.getAttribute('display-field')] || record.name;
- record.id = record[element.getAttribute('value-field')] || record.id;
- if(element.getAttribute('disabled-indicator') && record[element.getAttribute('disabled-indicator')]) {
- // The disabled-indicator equated to true, so we disable this option
- record.disabled = true;
- }
- if( record.group !== undefined && record.group !== null && record.site !== undefined && record.site !== null ) {
- results[record.site.name + ":" + record.group.name] = results[record.site.name + ":" + record.group.name] || { text: record.site.name + " / " + record.group.name, children: [] }
- results[record.site.name + ":" + record.group.name].children.push(record);
- }
- else if( record.group !== undefined && record.group !== null ) {
- results[record.group.name] = results[record.group.name] || { text: record.group.name, children: [] }
- results[record.group.name].children.push(record);
- }
- else if( record.site !== undefined && record.site !== null ) {
- results[record.site.name] = results[record.site.name] || { text: record.site.name, children: [] }
- results[record.site.name].children.push(record);
- }
- else if ( (record.group !== undefined || record.group == null) && (record.site !== undefined || record.site === null) ) {
- results['global'] = results['global'] || { text: 'Global', children: [] }
- results['global'].children.push(record);
- }
- else {
- results[idx] = record
- }
- return results;
- },Object.create(null));
- results = Object.values(results);
- // Handle the null option, but only add it once
- if (element.getAttribute('data-null-option') && data.previous === null) {
- var null_option = $(element).children()[0];
- results.unshift({
- id: null_option.value,
- text: null_option.text
- });
- }
- // Check if there are more results to page
- var page = data.next !== null;
- return {
- results: results,
- pagination: {
- more: page
- }
- };
- }
- }
- });
- // Flatpickr selectors
- $('.date-picker').flatpickr({
- allowInput: true
- });
- $('.datetime-picker').flatpickr({
- allowInput: true,
- enableSeconds: true,
- enableTime: true,
- time_24hr: true
- });
- $('.time-picker').flatpickr({
- allowInput: true,
- enableSeconds: true,
- enableTime: true,
- noCalendar: true,
- time_24hr: true
- });
- // API backed tags
- var tags = $('#id_tags');
- if (tags.length > 0 && tags.val().length > 0){
- tags = $('#id_tags').val().split(/,\s*/);
- } else {
- tags = [];
- }
- tag_objs = $.map(tags, function (tag) {
- return {
- id: tag,
- text: tag,
- selected: true
- }
- });
- // Replace the django issued text input with a select element
- $('#id_tags').replaceWith('<select name="tags" id="id_tags" class="form-control"></select>');
- $('#id_tags').select2({
- tags: true,
- data: tag_objs,
- multiple: true,
- allowClear: true,
- placeholder: "Tags",
- theme: "bootstrap",
- width: "off",
- ajax: {
- delay: 250,
- url: netbox_api_path + "extras/tags/",
- data: function(params) {
- // Paging. Note that `params.page` indexes at 1
- var offset = (params.page - 1) * 50 || 0;
- var parameters = {
- q: params.term,
- brief: 1,
- limit: 50,
- offset: offset,
- };
- return parameters;
- },
- processResults: function (data) {
- var results = $.map(data.results, function (obj) {
- // If tag contains space add double quotes
- if (/\s/.test(obj.name))
- obj.name = '"' + obj.name + '"'
- return {
- id: obj.name,
- text: obj.name
- }
- });
- // Check if there are more results to page
- var page = data.next !== null;
- return {
- results: results,
- pagination: {
- more: page
- }
- };
- }
- }
- });
- $('#id_tags').closest('form').submit(function(event){
- // django-taggit can only accept a single comma seperated string value
- var value = $('#id_tags').val();
- if (value.length > 0){
- var final_tags = value.join(', ');
- $('#id_tags').val(null).trigger('change');
- var option = new Option(final_tags, final_tags, true, true);
- $('#id_tags').append(option).trigger('change');
- }
- });
- if( $('select#id_mode').length > 0 ) {
- $('select#id_mode').on('change', function () {
- if ($(this).val() == '') {
- $('select#id_untagged_vlan').val();
- $('select#id_untagged_vlan').trigger('change');
- $('select#id_tagged_vlans').val([]);
- $('select#id_tagged_vlans').trigger('change');
- $('select#id_untagged_vlan').parent().parent().hide();
- $('select#id_tagged_vlans').parent().parent().hide();
- }
- else if ($(this).val() == 100) {
- $('select#id_tagged_vlans').val([]);
- $('select#id_tagged_vlans').trigger('change');
- $('select#id_untagged_vlan').parent().parent().show();
- $('select#id_tagged_vlans').parent().parent().hide();
- }
- else if ($(this).val() == 200) {
- $('select#id_untagged_vlan').parent().parent().show();
- $('select#id_tagged_vlans').parent().parent().show();
- }
- else if ($(this).val() == 300) {
- $('select#id_tagged_vlans').val([]);
- $('select#id_tagged_vlans').trigger('change');
- $('select#id_untagged_vlan').parent().parent().show();
- $('select#id_tagged_vlans').parent().parent().hide();
- }
- });
- $('select#id_mode').trigger('change');
- }
- // Scroll up an offset equal to the first nav element if a hash is present
- // Cannot use '#navbar' because it is not always visible, like in small windows
- function headerOffsetScroll() {
- if (window.location.hash) {
- // Short wait needed to allow the page to scroll to the element
- setTimeout(function() {
- window.scrollBy(0, -$('nav').height())
- }, 10);
- }
- }
- // Account for the header height when hash-scrolling
- window.addEventListener('load', headerOffsetScroll);
- window.addEventListener('hashchange', headerOffsetScroll);
- // Offset between the preview window and the window edges
- const IMAGE_PREVIEW_OFFSET_X = 20;
- const IMAGE_PREVIEW_OFFSET_Y = 10;
- // Preview an image attachment when the link is hovered over
- $('a.image-preview').on('mouseover', function(e) {
- // Twice the offset to account for all sides of the picture
- var maxWidth = window.innerWidth - (e.clientX + (IMAGE_PREVIEW_OFFSET_X * 2));
- var maxHeight = window.innerHeight - (e.clientY + (IMAGE_PREVIEW_OFFSET_Y * 2));
- var img = $('<img>').attr('id', 'image-preview-window').css({
- display: 'none',
- position: 'absolute',
- maxWidth: maxWidth + 'px',
- maxHeight: maxHeight + 'px',
- left: e.pageX + IMAGE_PREVIEW_OFFSET_X + 'px',
- top: e.pageY + IMAGE_PREVIEW_OFFSET_Y + 'px',
- boxShadow: '0 0px 12px 3px rgba(0, 0, 0, 0.4)',
- });
- // Remove any existing preview windows and add the current one
- $('#image-preview-window').remove();
- $('body').append(img);
- // Once loaded, show the preview if the image is indeed an image
- img.on('load', function(e) {
- if (e.target.complete && e.target.naturalWidth) {
- $('#image-preview-window').fadeIn('fast');
- }
- });
- // Begin loading
- img.attr('src', e.target.href);
- });
- // Fade the image out; it will be deleted when another one is previewed
- $('a.image-preview').on('mouseout', function() {
- $('#image-preview-window').fadeOut('fast');
- });
- });
|