Files
adsPRO/libraries/adspro-dialog.js
Jacek Pyziak bc75eab439 feat: add logs page with filtering and data table
- Implemented a new logs page with filters for level, source, and date range.
- Added a data table to display logs with pagination and sorting capabilities.
- Created backend functionality to fetch logs data based on filters.
- Introduced a new Logs class for handling log data operations.
- Added a new database migration for the logs table.
- Enhanced UI with custom checkbox styles for better user experience.
- Updated navigation to include a link to the logs page.
2026-02-21 13:05:59 +01:00

398 lines
10 KiB
JavaScript

/**
* AdsProDialog - własny system dialogów (zamiennik jquery-confirm)
* API kompatybilne z jquery-confirm: $.confirm(options), $.alert(options)
*/
(function( $ )
{
'use strict';
var dialogCounter = 0;
var activeDialogs = [];
function AdsProDialog( options )
{
this.id = ++dialogCounter;
this.options = $.extend( {}, AdsProDialog.defaults, options );
this.$el = null;
this.$box = null;
this.$content = null;
this._closed = false;
this._autoCloseTimer = null;
this._init();
}
AdsProDialog.defaults = {
title: '',
content: '',
type: '',
theme: '',
buttons: {},
closeIcon: false,
closeIconClass: 'fa-solid fa-xmark',
columnClass: '',
boxWidth: '',
useBootstrap: true,
draggable: false,
autoClose: '',
onContentReady: null,
onClose: null,
onOpen: null
};
AdsProDialog.prototype = {
_init: function()
{
this._buildDOM();
this._bindEvents();
this._appendToBody();
this._applyAutoClose();
this._triggerContentReady();
this._focusInitialElement();
activeDialogs.push( this );
},
_buildDOM: function()
{
var o = this.options;
var typeClass = o.type ? ' adspro-dialog-type-' + o.type : '';
var sizeStyle = '';
var sizeClass = '';
if ( !o.useBootstrap && o.boxWidth )
{
sizeStyle = 'max-width:' + o.boxWidth + ';width:100%;';
}
else if ( o.columnClass )
{
sizeClass = ' ' + o.columnClass.replace( /col-md-offset-\d+/g, '' ).trim();
}
var html =
'<div class="adspro-dialog" data-dialog-id="' + this.id + '">' +
'<div class="adspro-dialog-bg"></div>' +
'<div class="adspro-dialog-scrollpane">' +
'<div class="adspro-dialog-center' + sizeClass + '">' +
'<div class="adspro-dialog-box jconfirm-box' + typeClass + '" style="' + sizeStyle + '" tabindex="-1">' +
this._buildCloseIcon( o ) +
this._buildHeader( o ) +
'<div class="adspro-dialog-content-pane">' +
'<div class="adspro-dialog-content">' + o.content + '</div>' +
'</div>' +
this._buildButtons( o ) +
'<div class="adspro-dialog-loading" style="display:none;">' +
'<div class="adspro-dialog-spinner"></div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
this.$el = $( html );
this.$box = this.$el.find( '.adspro-dialog-box' );
this.$content = this.$el.find( '.adspro-dialog-content' );
},
_buildCloseIcon: function( o )
{
if ( !o.closeIcon ) return '';
var iconClass = o.closeIconClass || 'fa-solid fa-xmark';
return '<div class="adspro-dialog-close-icon"><i class="' + iconClass + '"></i></div>';
},
_buildHeader: function( o )
{
if ( !o.title ) return '';
return '<div class="adspro-dialog-title-c">' +
'<span class="adspro-dialog-title">' + o.title + '</span>' +
'</div>';
},
_buildButtons: function( o )
{
if ( !o.buttons || $.isEmptyObject( o.buttons ) ) return '';
var html = '<div class="adspro-dialog-buttons">';
var self = this;
$.each( o.buttons, function( key, btnDef )
{
if ( typeof btnDef === 'function' )
{
btnDef = { action: btnDef };
o.buttons[ key ] = btnDef;
}
var text = btnDef.text || key.charAt( 0 ).toUpperCase() + key.slice( 1 );
var btnClass = btnDef.btnClass || 'btn-default';
var isEnter = ( btnDef.keys && btnDef.keys.indexOf( 'enter' ) !== -1 );
html += '<button type="button" class="adspro-dialog-btn btn ' + btnClass + '"' +
' data-btn-key="' + key + '"' +
( isEnter ? ' data-enter-key="true"' : '' ) +
'>' + text + '</button>';
});
html += '</div>';
return html;
},
_bindEvents: function()
{
var self = this;
var o = this.options;
// Backdrop click
this.$el.find( '.adspro-dialog-bg' ).on( 'click', function()
{
self.close();
});
// Close icon
this.$el.find( '.adspro-dialog-close-icon' ).on( 'click', function()
{
self.close();
});
// Buttons
this.$el.find( '.adspro-dialog-btn' ).each( function()
{
var $btn = $( this );
var key = $btn.data( 'btn-key' );
var btnDef = o.buttons[ key ];
// Referencje do buttonów (kompatybilność z $$formSubmit itp.)
self[ '$$' + key ] = $btn;
$btn.on( 'click', function()
{
if ( typeof btnDef === 'function' )
{
btnDef.call( self );
self.close();
return;
}
if ( btnDef && typeof btnDef.action === 'function' )
{
var result = btnDef.action.call( self );
if ( result !== false )
{
self.close();
}
}
else
{
self.close();
}
});
});
// Keyboard
$( document ).on( 'keydown.adspro-dialog-' + this.id, function( e )
{
if ( self._closed ) return;
if ( activeDialogs[ activeDialogs.length - 1 ] !== self ) return;
if ( e.key === 'Escape' )
{
e.preventDefault();
self.close();
}
if ( e.key === 'Enter' )
{
if ( $( e.target ).is( '.adspro-dialog-btn, textarea, select, input' ) ) return;
var $enterBtn = self.$el.find( '.adspro-dialog-btn[data-enter-key="true"]' );
if ( $enterBtn.length )
{
e.preventDefault();
$enterBtn.trigger( 'click' );
}
}
});
// Draggable
if ( o.draggable && $.fn.draggable )
{
this.$box.draggable({
handle: '.adspro-dialog-title-c',
cursor: 'move'
});
this.$el.find( '.adspro-dialog-title-c' ).css( 'cursor', 'move' );
}
},
_appendToBody: function()
{
var baseZIndex = 99000 + ( this.id * 10 );
this.$el.css( 'z-index', baseZIndex );
$( 'body' ).append( this.$el );
var self = this;
requestAnimationFrame( function()
{
self.$el.addClass( 'adspro-dialog-open' );
});
if ( typeof this.options.onOpen === 'function' )
{
this.options.onOpen.call( this );
}
},
_applyAutoClose: function()
{
var ac = this.options.autoClose;
if ( !ac ) return;
var parts = ac.split( '|' );
if ( parts.length !== 2 ) return;
var ms = parseInt( parts[ 1 ], 10 );
var self = this;
this._autoCloseTimer = setTimeout( function()
{
if ( !self._closed ) self.close();
}, ms );
},
_triggerContentReady: function()
{
if ( typeof this.options.onContentReady === 'function' )
{
this.options.onContentReady.call( this );
}
},
_focusInitialElement: function()
{
var self = this;
setTimeout( function()
{
if ( self._closed ) return;
if ( $( document.activeElement ).closest( self.$el ).length ) return;
var $focusTarget = self.$el.find( '[autofocus]:visible:not(:disabled):first' );
if ( !$focusTarget.length )
{
$focusTarget = self.$el.find( '.adspro-dialog-content input:visible:not(:disabled):first, .adspro-dialog-content select:visible:not(:disabled):first, .adspro-dialog-content textarea:visible:not(:disabled):first' ).first();
}
if ( !$focusTarget.length )
{
$focusTarget = self.$el.find( '.adspro-dialog-btn[data-enter-key="true"]:visible:not(:disabled):first' );
}
if ( !$focusTarget.length )
{
$focusTarget = self.$el.find( '.adspro-dialog-btn:visible:not(:disabled):first' );
}
if ( !$focusTarget.length )
{
$focusTarget = self.$box;
}
if ( $focusTarget.length )
{
$focusTarget.trigger( 'focus' );
}
}, 20 );
},
// --- Metody publiczne ---
close: function()
{
if ( this._closed ) return;
this._closed = true;
if ( this._autoCloseTimer ) clearTimeout( this._autoCloseTimer );
$( document ).off( 'keydown.adspro-dialog-' + this.id );
var self = this;
this.$el.removeClass( 'adspro-dialog-open' );
this.$el.addClass( 'adspro-dialog-closing' );
setTimeout( function()
{
self.$el.remove();
var idx = activeDialogs.indexOf( self );
if ( idx > -1 ) activeDialogs.splice( idx, 1 );
if ( typeof self.options.onClose === 'function' )
{
self.options.onClose.call( self );
}
}, 250 );
},
showLoading: function( showContent )
{
this.$el.find( '.adspro-dialog-loading' ).show();
if ( !showContent )
{
this.$el.find( '.adspro-dialog-content-pane' ).css( 'opacity', '0.3' );
}
this.$el.find( '.adspro-dialog-buttons' ).css({
'pointer-events': 'none',
'opacity': '0.5'
});
},
hideLoading: function()
{
this.$el.find( '.adspro-dialog-loading' ).hide();
this.$el.find( '.adspro-dialog-content-pane' ).css( 'opacity', '' );
this.$el.find( '.adspro-dialog-buttons' ).css({
'pointer-events': '',
'opacity': ''
});
},
setContent: function( html )
{
this.$content.html( html );
},
setTitle: function( title )
{
this.$el.find( '.adspro-dialog-title' ).html( title );
}
};
// --- Rejestracja globalna ---
$.confirm = function( options )
{
return new AdsProDialog( options );
};
$.alert = function( options )
{
if ( typeof options === 'string' )
{
options = {
title: '',
content: options,
buttons: { ok: { text: 'OK', btnClass: 'btn-blue' } }
};
}
if ( !options.buttons )
{
options.buttons = { ok: { text: 'OK', btnClass: 'btn-blue' } };
}
return new AdsProDialog( options );
};
$.dialog = function( options )
{
options = options || {};
options.closeIcon = true;
if ( !options.buttons )
{
options.buttons = {};
}
return new AdsProDialog( options );
};
})( jQuery );