Question responses
What would be your method to improve the management of multiple functions?
Looking at the three functions that call dialog_Handler() it appears that the main redundancies are with the click handlers for the buttons. See the response to the question below for one technique to simplify that logic.
In a comment, you asked:
Do you know if there is any way to call $(this).dialog("close"); without writing it inside each function(){ } of the var buttons?
Yes, you can abstract the function of closing the dialog out to a separate function, like:
function closeDialog() {
$(this).dialog("close");
}
And that function can be bound to the functions for the button handlers using the Javascript function .bind() to create a partially applied function for the funk_Ok parameter:
var buttons = {
"Ok": closeDialog.bind(null, funk_Ok),
"Cancel": closeDialog
}
And that close function could accept an optional callback function (for functions like func_Ok)- if that is a function, it can be called:
function closeDialog(callback) {
(typeof callback === "function") && callback();
$(this).dialog("close");
}
But the problem here is that this in this context is not the same as before - it is the window object. So one solution is to give the HTML element wrapped in the dialog object an id attribute, like below:
const dialogId = 'message_dialog';
function dialog_Handler({
title,
message,
buttons,
input
}) {
$("<p id='"+dialogId+"'>" + message + "</p>").dialog({ // Could use “var dialog = ”
And then in the closeDialog function, just reference that id attribute when closing the dialog:
function closeDialog(callback) {
(typeof callback === "function") && callback();
$('#'+dialogId).dialog("close");
}
See this in action in the snippet below:
Edit:
The code can be simplified by using Object.assign()- each function call to dialog_Handler() can use that to assign the button on the object that gets destructured:
dialog_Handler(Object.assign(arguments[0], {buttons: buttons}));
Then each function can omit the object properties it doesn't use (e.g. message, title)...
//could use const
var dialogId = 'dialogContainer';
// jQuery UI dialog custom management
function dialog_Handler({
title,
message,
buttons,
input
}) {
$("<p id='"+dialogId+"'>" + message + "</p>").dialog({ // Could use “var dialog = ”
//autoOpen: false, // false would prevents regular opening
show: "drop",
open: function(event, ui) {
// Overlay parameterization
$("div.ui-widget-overlay").css({
"background": "#000",
"opacity": "0.4"
});
$(".ui-widget-overlay").hide().fadeIn();
// Adds some more configuration if input needed
if (input) {
// Adds input field right under the message
$(this).append('<br /><br /><input id="dialog_Input" style="width: 350px; padding: 4px;" type="text" value="' + input + '"><br />');
// Binds “Enter” to press first button (usually “Ok”)
$(this).keydown(function(event) {
if (event.keyCode == $.ui.keyCode.ENTER) {
$(this).parent().find("button:eq(1)").trigger("click");
return false;
}
});
}
},
title: title,
buttons: buttons,
modal: true,
resizable: false,
height: "auto",
width: 400,
hide: {
effect: "drop",
duration: "fast"
},
closeOnEscape: true,
// Overlay fadeout
beforeClose: function(event, ui) {
// Wait for the overlay to be faded out to try closing again
if ($('.ui-widget-overlay').is(":visible")) {
$('.ui-widget-overlay').fadeOut("fast", function() {
$('.ui-widget-overlay').hide();
$('.ui-icon-closethick').trigger('click');
});
return false;
}
},
close: function() {
$(this).dialog("destroy");
}
});
return;
}
function closeDialog(callback) {
(typeof callback === "function") && callback();
$('#'+dialogId).dialog("close");
}
function dialog_OkCancel({
funk_Ok
}) {
var buttons = {
"Ok": closeDialog.bind(null, funk_Ok),
"Cancel": closeDialog
}
dialog_Handler(Object.assign(arguments[0], {buttons: buttons}));
return;
}
function dialog_Input_OkCancel({
input,
funk_Ok
}) {
var buttons = {
"Ok": closeDialog.bind(null, funk_Ok),
"Cancel": closeDialog
}
dialog_Handler(Object.assign(arguments[0], {buttons: buttons}));
return;
}
function dialog_YesNoCancel({
funk_Yes,
funk_No
}) {
var buttons = {
"Yes": closeDialog.bind(null, funk_Yes),
"No": closeDialog.bind(null, funk_No),
"Cancel": closeDialog
}
dialog_Handler(Object.assign(arguments[0], {buttons: buttons}));
return;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" />
<button class="dialog" onclick='dialog_OkCancel({
title: "Title",
message: "I do not have any idea for the message.",
funk_Ok: function(){ console.log("Sorry. :("); }
});'>Dialog<br>Ok/Cancel</button>
<button class="dialog" onclick='dialog_Input_OkCancel({
title: "Title",
message: "I do not have any idea for the message.",
input: "Type something…",
funk_Ok: function(){ console.log("Give me more words ! :)"); }
});'>Dialog<br>Input</button>
<button class="dialog" onclick='dialog_YesNoCancel({
title: "Just talking…",
message: "Are you fine?",
funk_Yes: function(){ console.log("You said “Yes”! :)"); },
funk_No: function(){ console.log("You said “No”! :("); }
});'>Dialog<br>Yes/No/Cancel</button>
One could also create a hidden element in the DOM, have dialog_Handler() update the text/HTML of that element and show it (using .show() - or toggle a class name that shows it), then hide it (using .hide()) when destroying the dialog. That way, the abstracted close function can just utilize that element.
//could use const
var dialogContainer = $('#dialogContainer');
// jQuery UI dialog custom management
function dialog_Handler({
title,
message,
buttons,
input
}) {
dialogContainer.text(message).show().dialog({ // Could use “var dialog = ”
//autoOpen: false, // false would prevents regular opening
show: "drop",
open: function(event, ui) {
// Overlay parameterization
$("div.ui-widget-overlay").css({
"background": "#000",
"opacity": "0.4"
});
$(".ui-widget-overlay").hide().fadeIn();
// Adds some more configuration if input needed
if (input) {
// Adds input field right under the message
$(this).append('<br /><br /><input id="dialog_Input" style="width: 350px; padding: 4px;" type="text" value="' + input + '"><br />');
// Binds “Enter” to press first button (usually “Ok”)
$(this).keydown(function(event) {
if (event.keyCode == $.ui.keyCode.ENTER) {
$(this).parent().find("button:eq(1)").trigger("click");
return false;
}
});
}
},
title: title,
buttons: buttons,
modal: true,
resizable: false,
height: "auto",
width: 400,
hide: {
effect: "drop",
duration: "fast"
},
closeOnEscape: true,
// Overlay fadeout
beforeClose: function(event, ui) {
// Wait for the overlay to be faded out to try closing again
if ($('.ui-widget-overlay').is(":visible")) {
$('.ui-widget-overlay').fadeOut("fast", function() {
$('.ui-widget-overlay').hide();
$('.ui-icon-closethick').trigger('click');
});
return false;
}
},
close: function() {
$(this).dialog("destroy");
dialogContainer.hide();
}
});
return;
}
function closeDialog(callback) {
(typeof callback === "function") && callback();
dialogContainer.dialog("close");
}
function dialog_OkCancel({
funk_Ok
}) {
var buttons = {
"Ok": closeDialog.bind(null, funk_Ok),
"Cancel": closeDialog
}
dialog_Handler(Object.assign(arguments[0], {buttons: buttons}));
return;
}
function dialog_Input_OkCancel({
input,
funk_Ok
}) {
var buttons = {
"Ok": closeDialog.bind(null, funk_Ok),
"Cancel": closeDialog
}
dialog_Handler(Object.assign(arguments[0], {buttons: buttons}));
return;
}
function dialog_YesNoCancel({
funk_Yes,
funk_No
}) {
var buttons = {
"Yes": closeDialog.bind(null, funk_Yes),
"No": closeDialog.bind(null, funk_No),
"Cancel": closeDialog
}
dialog_Handler(Object.assign(arguments[0], {buttons: buttons}));
return;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" />
<p id="dialogContainer" style="display: none"></p>
<button class="dialog" onclick='dialog_OkCancel({
title: "Title",
message: "I do not have any idea for the message.",
funk_Ok: function(){ console.log("Sorry. :("); }
});'>Dialog<br>Ok/Cancel</button>
<button class="dialog" onclick='dialog_Input_OkCancel({
title: "Title",
message: "I do not have any idea for the message.",
input: "Type something…",
funk_Ok: function(){ console.log("Give me more words ! :)"); }
});'>Dialog<br>Input</button>
<button class="dialog" onclick='dialog_YesNoCancel({
title: "Just talking…",
message: "Are you fine?",
funk_Yes: function(){ console.log("You said “Yes”! :)"); },
funk_No: function(){ console.log("You said “No”! :("); }
});'>Dialog<br>Yes/No/Cancel</button>
Other Review points
Feedback
I like the usage of the jQuery ui keycode constant for the enter key (i.e. if (event.keyCode == $.ui.keyCode.ENTER) {). I must admit I hadn't used that before but aim to do so in the future.
I really like the application of object destructuring for passing the named parameters - that is quite nifty!
Suggestions
Cache DOM references
I see a couple places where DOM elements are looked up in succession, for example:
if ($('.ui-widget-overlay').is(":visible")) {
$('.ui-widget-overlay').fadeOut("fast", function() {
$('.ui-widget-overlay').hide();
$('.ui-icon-closethick').trigger('click');
});
return false;
}
It is wise to cache those lookups in a variable - or actually, use const to declare a constant unless there is a need to re-assign that value...
const widgetOverlay = $('.ui-widget-overlay');
// Wait for the overlay to be faded out to try closing again
if (widgetOverlay.is(":visible")) {
widgetOverlay.fadeOut("fast", function() {
widgetOverlay.hide();
$('.ui-icon-closethick').trigger('click');
});
return false;
}
Placeholder text
I would use the placeholder attribute instead of the value attribute of the text input, since it appears that text is really prompting the user...
<input type="text" placeholder="Type some text here..." />