Skip to content

Commit 7e3e450

Browse files
authored
feat(modal): dynamic modal content
This PR adds the same dynamic functionality like toast to create a modal just out of properties or reuse a DOM node modal as a template with its content being dynamically set via js properties. Everything is optional and backward compatible 🙂 Most of the code is copied /adopted from the toast component so the usage is equal. This goes along with @prudho fui-alert plugin approach (#1716) which could be more simplified then Create a temporary modal just by JS properties By providing new properties to the modal module and targeting to body you create temporary modals without the need to create markup on your own. The modal is temporary and will be removed from the DOM once closed. $('body').modal({ title: 'Important Notice', class: 'mini', closeIcon: true, content: 'You will be logged out in 5 Minutes', actions: [{ text: 'Alright, got it', class: 'green' }] }).modal('show'); Reuse an existing modal Also, you can still prepare a modal markup in your domtree as usual, but set the related content via js properties to reuse the general style $('.ui.modal').modal({ title: 'Chat rules', content: '<div>You can put HTML content right here</div>', class: 'inverted fullscreen', classContent: 'scrolling', actions: [{ text: 'That is awesome', class: 'green', icon: 'exclamation', click: function() { // do something. return false to prevent closing the modal } }] }).modal('show');
1 parent b41338d commit 7e3e450

File tree

1 file changed

+117
-6
lines changed

1 file changed

+117
-6
lines changed

src/definitions/modules/modal.js

Lines changed: 117 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ $.fn.modal = function(parameters) {
5858
selector = settings.selector,
5959
className = settings.className,
6060
namespace = settings.namespace,
61+
fields = settings.fields,
6162
error = settings.error,
6263

6364
eventNamespace = '.' + namespace,
@@ -74,7 +75,7 @@ $.fn.modal = function(parameters) {
7475
$dimmer,
7576

7677
element = this,
77-
instance = $module.data(moduleNamespace),
78+
instance = $module.hasClass('modal') ? $module.data(moduleNamespace) : undefined,
7879

7980
ignoreRepeatedEvents = false,
8081

@@ -91,6 +92,41 @@ $.fn.modal = function(parameters) {
9192
module = {
9293

9394
initialize: function() {
95+
if(!$module.hasClass('modal')) {
96+
module.create.modal();
97+
if(!$.isFunction(settings.onHidden)) {
98+
settings.onHidden = function () {
99+
module.destroy();
100+
$module.remove();
101+
};
102+
}
103+
}
104+
$module.addClass(settings.class);
105+
if (settings.title !== '') {
106+
$module.find(selector.title).html(module.helpers.escape(settings.title, settings.preserveHTML)).addClass(settings.classTitle);
107+
}
108+
if (settings.content !== '') {
109+
$module.find(selector.content).html(module.helpers.escape(settings.content, settings.preserveHTML)).addClass(settings.classContent);
110+
}
111+
if(module.has.configActions()){
112+
var $actions = $module.find(selector.actions).addClass(settings.classActions);
113+
settings.actions.forEach(function (el) {
114+
var icon = el[fields.icon] ? '<i class="' + module.helpers.deQuote(el[fields.icon]) + ' icon"></i>' : '',
115+
text = module.helpers.escape(el[fields.text] || '', settings.preserveHTML),
116+
cls = module.helpers.deQuote(el[fields.class] || ''),
117+
click = el[fields.click] && $.isFunction(el[fields.click]) ? el[fields.click] : function () {};
118+
$actions.append($('<button/>', {
119+
html: icon + text,
120+
class: className.button + ' ' + cls,
121+
click: function () {
122+
if (click.call(element, $module) === false) {
123+
return;
124+
}
125+
module.hide();
126+
}
127+
}));
128+
});
129+
}
94130
module.cache = {};
95131
module.verbose('Initializing dimmer', $context);
96132

@@ -121,6 +157,23 @@ $.fn.modal = function(parameters) {
121157
},
122158

123159
create: {
160+
modal: function() {
161+
$module = $('<div/>', {class: 'ui modal'});
162+
if (settings.closeIcon) {
163+
$close = $('<i/>', {class: className.close})
164+
$module.append($close);
165+
}
166+
if (settings.title !== '') {
167+
$('<div/>', {class: 'header'}).appendTo($module);
168+
}
169+
if (settings.content !== '') {
170+
$('<div/>', {class: 'content'}).appendTo($module);
171+
}
172+
if (module.has.configActions()) {
173+
$('<div/>', {class: 'actions'}).appendTo($module);
174+
}
175+
$context.append($module);
176+
},
124177
dimmer: function() {
125178
var
126179
defaultSettings = {
@@ -499,7 +552,9 @@ $.fn.modal = function(parameters) {
499552
$previousModal.find(selector.dimmer).removeClass('active');
500553
}
501554
}
502-
settings.onHidden.call(element);
555+
if($.isFunction(settings.onHidden)) {
556+
settings.onHidden.call(element);
557+
}
503558
module.remove.dimmerStyles();
504559
module.restore.focus();
505560
callback();
@@ -699,7 +754,35 @@ $.fn.modal = function(parameters) {
699754
$module.removeClass(className.loading);
700755
module.debug('Caching modal and container sizes', module.cache);
701756
},
702-
757+
helpers: {
758+
deQuote: function(string) {
759+
return String(string).replace(/"/g,"");
760+
},
761+
escape: function(string, preserveHTML) {
762+
if (preserveHTML){
763+
return string;
764+
}
765+
var
766+
badChars = /[<>"'`]/g,
767+
shouldEscape = /[&<>"'`]/,
768+
escape = {
769+
"<": "&lt;",
770+
">": "&gt;",
771+
'"': "&quot;",
772+
"'": "&#x27;",
773+
"`": "&#x60;"
774+
},
775+
escapedChar = function(chr) {
776+
return escape[chr];
777+
}
778+
;
779+
if(shouldEscape.test(string)) {
780+
string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&amp;");
781+
return string.replace(badChars, escapedChar);
782+
}
783+
return string;
784+
}
785+
},
703786
can: {
704787
leftBodyScrollbar: function(){
705788
if(module.cache.leftBodyScrollbar === undefined) {
@@ -734,7 +817,11 @@ $.fn.modal = function(parameters) {
734817
;
735818
}
736819
},
737-
820+
has: {
821+
configActions: function () {
822+
return Array.isArray(settings.actions) && settings.actions.length > 0;
823+
}
824+
},
738825
is: {
739826
active: function() {
740827
return $module.hasClass(className.active);
@@ -1107,6 +1194,7 @@ $.fn.modal = function(parameters) {
11071194
instance.invoke('destroy');
11081195
}
11091196
module.initialize();
1197+
returnedValue = $module;
11101198
}
11111199
})
11121200
;
@@ -1161,6 +1249,24 @@ $.fn.modal.settings = {
11611249
padding : 50,
11621250
scrollbarWidth: 10,
11631251

1252+
//dynamic content
1253+
title : '',
1254+
content : '',
1255+
class : '',
1256+
classTitle : '',
1257+
classContent : '',
1258+
classActions : '',
1259+
closeIcon : false,
1260+
actions : false,
1261+
preserveHTML : true,
1262+
1263+
fields : {
1264+
class : 'class',
1265+
text : 'text',
1266+
icon : 'icon',
1267+
click : 'click'
1268+
},
1269+
11641270
// called before show animation
11651271
onShow : function(){},
11661272

@@ -1171,7 +1277,7 @@ $.fn.modal.settings = {
11711277
onHide : function(){ return true; },
11721278

11731279
// called after hide animation
1174-
onHidden : function(){},
1280+
onHidden : false,
11751281

11761282
// called after approve selector match
11771283
onApprove : function(){ return true; },
@@ -1180,6 +1286,9 @@ $.fn.modal.settings = {
11801286
onDeny : function(){ return true; },
11811287

11821288
selector : {
1289+
title : '> .header',
1290+
content : '> .content',
1291+
actions : '> .actions',
11831292
close : '> .close',
11841293
approve : '.actions .positive, .actions .approve, .actions .ok',
11851294
deny : '.actions .negative, .actions .deny, .actions .cancel',
@@ -1201,7 +1310,9 @@ $.fn.modal.settings = {
12011310
loading : 'loading',
12021311
scrolling : 'scrolling',
12031312
undetached : 'undetached',
1204-
front : 'front'
1313+
front : 'front',
1314+
close : 'close icon',
1315+
button : 'ui button'
12051316
}
12061317
};
12071318

0 commit comments

Comments
 (0)