static/midcom.workflow/workflow.js   C
last analyzed

Complexity

Total Complexity 53
Complexity/F 1.83

Size

Lines of Code 338
Function Count 29

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 53
eloc 237
c 0
b 0
f 0
dl 0
loc 338
rs 6.96
mnd 24
bc 24
fnc 29
bpm 0.8275
cpm 1.8275
noi 1

4 Functions

Rating   Name   Duplication   Size   Complexity  
D workflow.js ➔ render 0 7 12
B workflow.js ➔ make_dialog 0 32 7
F workflow.js ➔ create_dialog 0 138 20
F workflow.js ➔ get_spinner_template 0 3 14

How to fix   Complexity   

Complexity

Complex classes like static/midcom.workflow/workflow.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
$(document).ready(function() {
2
    $('body').on('click', '[data-dialog="delete"]', function(event) {
3
        event.preventDefault();
4
        var button = $(this),
5
            dialog = $('<div class="midcom-delete-dialog">'),
6
            spinner = $('<div class="spinner">' + get_spinner_template() + '</div>'),
7
            text = this.dataset.dialogText,
8
            relocate = $(this).data('relocate'),
9
            action = this.getAttribute('href') || this.dataset.action,
10
            options = {
11
                title:  this.dataset.dialogHeading,
12
                dialogClass: 'midcom-workflow-dialog midcom-workflow-dialog-delete',
13
                modal: true,
14
                width: 'auto',
15
                maxHeight: $(window).height(),
16
                buttons: [{
17
                    text: button.text().trim() || this.dataset.dialogHeading,
18
                    click: function() {
19
                        if (relocate) {
20
                            $('<form action="' + action + '" method="post" class="midcom-dialog-delete-form">')
21
                                .append($('<input type="submit" name="' + button.data('form-id') + '">'))
22
                                .append($('<input type="hidden" name="referrer" value="' + location.pathname + '">'))
23
                                .hide()
24
                                .prependTo('body');
25
                            $('input[name="' + button.data('form-id') + '"]').click();
26
                        } else {
27
                            var params = {
28
                                referrer: location.pathname
29
                            };
30
                            params[button.data('form-id')] = 1;
31
32
                            $.post(action, params).done(function(message) {
33
                                button.trigger('dialogdeleted', [message]);
34
                                dialog.dialog("close");
35
                                if (   typeof window.parent.$ !== "undefined"
36
                                    && window.parent.$('#midcom-dialog').length > 0 ) {
37
                                    window.parent.$('#midcom-dialog')
38
                                        .dialog('close')
39
                                        .trigger('dialogdeleted', [message]);
40
                                }
41
                            });
42
                        }
43
                    }
44
                }, {
45
                    text: this.dataset.dialogCancelLabel,
46
                    click: function() {
47
                        $(this).dialog("close");
48
                    }
49
                }]
50
            };
51
52
        if ($('.midcom-delete-dialog').length > 0) {
53
            $('.midcom-delete-dialog').remove();
54
        }
55
56
        if (this.dataset.recursive === 'true') {
57
            dialog.addClass('loading');
58
            options.buttons[0].disabled = true;
59
            $.getJSON(MIDCOM_PAGE_PREFIX + 'midcom-exec-midcom.helper.reflector/list-children.php',
60
                {guid: this.dataset.guid},
61
                function (data) {
62
                    function render(carry, item) {
63
                        carry += '<li class="leaf ' + item['class'] + '">' + item.icon + ' ' + item.title;
64
                        if (item.children) {
65
                            carry += item.children.reduce(render, '<ul class="folder_list">') + '</ul>';
66
                        }
67
                        return carry + '</li>';
68
                    }
69
70
                    if (data.length > 0) {
71
                        $('<ul class="folder_list">')
72
                            .append($(data.reduce(render, '')))
73
                            .appendTo($('#delete-child-list'));
74
                    } else {
75
                        dialog.find('p.warning').hide();
76
                    }
77
                    options.buttons[0].disabled = false;
78
79
                    dialog
80
                        .removeClass('loading')
81
                        .dialog('option', 'position', dialog.dialog('option', 'position'))
82
                        .dialog('option', 'buttons', options.buttons)
83
                        .focus();
84
                });
85
        } else {
86
            text = '<p>' + text + '</p>';
87
        }
88
89
        dialog
90
            .css('min-width', '300px') // This should be handled by dialog's minWidth option, but that doesn't work with width: "auto"
91
                                       // Should be fixed in https://github.com/jquery/jquery-ui/commit/643b80c6070e2eba700a09a5b7b9717ea7551005
92
            .append($(text))
93
            .append(spinner)
94
            .appendTo($('body'));
95
96
        make_dialog(dialog, options);
97
        dialog.on( "dialogclose", function() {
98
            button.parent()
99
                .find('.ui-state-disabled')
100
                .removeClass('ui-state-disabled');
101
        });
102
    });
103
104
    $('body').on('click', '[data-dialog="dialog"]', function(event) {
105
        event.preventDefault();
106
        let url;
107
        if ($('.midcom-workflow-dialog').is(':visible') && $('.midcom-workflow-dialog iframe').length > 0) {
108
            url = $('.midcom-workflow-dialog iframe')[0].contentWindow.location.href;
109
        }
110
        if (url != this.href) {
0 ignored issues
show
Bug introduced by
The variable url does not seem to be initialized in case $(".midcom-workflow-dial...log iframe").length > 0 on line 107 is false. Are you sure this can never be the case?
Loading history...
111
            create_dialog($(this), $(this).find('.toolbar_label').text() || this.title, this.getAttribute('href'));
112
        }
113
    });
114
115
    $('body').on('click', '[data-dialog="confirm"]', function(event) {
116
        event.preventDefault();
117
        var button = $(this),
118
            dialog = $('<div class="midcom-confirm-dialog">'),
119
            options = {
120
                title:  this.dataset.dialogHeading,
121
                modal: true,
122
                width: 'auto',
123
                maxHeight: $(window).height(),
124
                buttons: [{
125
                    text: this.dataset.dialogConfirmLabel,
126
                    click: function() {
127
                        button.closest('form').submit();
128
                    }
129
                }, {
130
                    text: this.dataset.dialogCancelLabel,
131
                    click: function() {
132
                        $(this).dialog("close");
133
                    }
134
                }]
135
            };
136
137
        if ($('.midcom-confirm-dialog').length > 0) {
138
            $('.midcom-confirm-dialog').remove();
139
        }
140
141
        dialog
142
            .css('min-width', '300px') // This should be handled by dialog's minWidth option, but that doesn't work with width: "auto"
143
                                       // Should be fixed in https://github.com/jquery/jquery-ui/commit/643b80c6070e2eba700a09a5b7b9717ea7551005
144
            .append($('<p>' + this.dataset.dialogText + '</p>'))
145
            .appendTo($('body'));
146
        make_dialog(dialog, options);
147
    });
148
    $('body').on('click', '.midcom-workflow-dialog .ui-dialog-buttonpane .ui-button', function() {
149
        var pane = $(this).closest('.ui-dialog-buttonpane'),
150
            iframe = pane.prevAll('#midcom-dialog').find('iframe'),
151
            disabler = function() {
152
                pane.find('.ui-button')
153
                    .addClass('ui-state-disabled');
154
            };
155
156
        if (!$(this).hasClass('dialog-extra-button') && $('form.datamanager2', iframe.contents()).length > 0) {
157
            $('form.datamanager2', iframe.contents()).on('submit', disabler);
158
        } else {
159
            disabler();
160
        }
161
    });
162
});
163
164
function get_spinner_template() {
165
    return typeof WORKFLOW_SPINNER_TEMPLATE != 'undefined' ? WORKFLOW_SPINNER_TEMPLATE : '<i class="fa fa-pulse fa-spinner"></i>';
166
}
167
168
function create_dialog(control, title, url) {
169
    if ($('.midcom-workflow-dialog').is(':visible')) {
170
        $('body').addClass('midcom-workflow-switching');
171
        $('.midcom-workflow-dialog .ui-dialog-content').dialog('close');
172
    }
173
174
    var dialog, iframe, spinner, is_scrolling,
175
        config = {
176
            dialogClass: 'midcom-workflow-dialog',
177
            buttons: [],
178
            title: title,
179
            height:  590,
180
            width: 800,
181
            close: function() {
182
                control.removeClass('active');
183
                iframe.css('visibility', 'hidden');
184
                // second clause is an IE11 workaround
185
                if (iframe[0].contentWindow && iframe[0].contentWindow.hasOwnProperty('stop')) {
186
                    iframe[0].contentWindow.stop();
187
                }
188
                if ($('body').hasClass('midcom-workflow-switching')) {
189
                    $('body').removeClass('midcom-workflow-switching');
190
                } else {
191
                    $('body').removeClass('midcom-workflow-active');
192
                }
193
            },
194
            open: function() {
195
                dialog.closest('.ui-dialog').focus();
196
                $('body').addClass('midcom-workflow-active');
197
            }};
198
199
    if (control.data('dialog-cancel-label')) {
200
        config.buttons.push({
201
            text: control.data('dialog-cancel-label'),
202
            click: function() {
203
                $(this).dialog( "close" );
204
            }
205
        });
206
    }
207
208
    // Workaround for jqueryui incompatibility between position widget & css fixed position
209
    function keep_dialog_fixed () {
210
        var ui_dialog = dialog.closest('.ui-dialog'),
211
            viewport_position = ui_dialog[0].getBoundingClientRect();
212
213
        window.clearTimeout(is_scrolling);
214
215
        ui_dialog.css({
216
            position: 'fixed',
217
            top: viewport_position.top + 'px',
218
            left: viewport_position.left + 'px'
219
        });
220
221
        is_scrolling = setTimeout(function() {
222
            ui_dialog.css({
223
                position: 'absolute',
224
                top: ui_dialog.offset().top + 'px',
225
                left: ui_dialog.offset().left + 'px'
226
            });
227
        }, 500);
228
    }
229
230
    if ($('#midcom-dialog').length > 0) {
231
        dialog = $('#midcom-dialog');
232
        iframe = dialog.find('> iframe');
233
        spinner = dialog.find('> .spinner').show();
234
        config.height = dialog.dialog('option', 'height');
235
        config.width = dialog.dialog('option', 'width');
236
        if (   config.width > window.innerWidth
237
            || config.height > window.innerHeight) {
238
            config.position = { my: "center", at: "center", of: window, collision: 'flipfit' };
239
        }
240
    } else {
241
        spinner = $('<span class="spinner">' + get_spinner_template() + '</span>');
242
        iframe = $('<iframe name="datamanager-dialog"'
243
                   + ' frameborder="0"'
244
                   + ' width="100%"'
245
                   + ' height="100%"'
246
                   + ' scrolling="auto"></iframe>')
247
           .on('load', function() {
248
               // this is only here as fallback in case dialog.js doesn't run for whatever reason
249
               spinner.hide();
250
               this.style.visibility = 'visible';
251
           });
252
253
        dialog = $('<div id="midcom-dialog" class="has-iframe"></div>')
254
            .append(spinner)
255
            .append(iframe)
256
            .on('dialogcreate', function() {
257
                var maximized = false,
258
                    saved_options = {};
259
                $(this).prevAll('.ui-dialog-titlebar').on('dblclick', function() {
260
                    if (!maximized) {
261
                        saved_options.position = dialog.dialog('option', 'position');
262
                        saved_options.width = dialog.dialog('option', 'width');
263
                        saved_options.height = dialog.dialog('option', 'height');
264
                        dialog.dialog('option', {
265
                            width: '99%',
266
                            height: $(window).height(),
267
                            position: {my: 'center top', at: 'center top', of: window}
268
                        });
269
                        maximized = true;
270
                    } else {
271
                        dialog.dialog('option', {
272
                            height: saved_options.height,
273
                            width: saved_options.width,
274
                            position: saved_options.position
275
                        });
276
                        maximized = false;
277
                    }
278
                });
279
            })
280
            .on('dialogopen', function() {
281
                window.addEventListener('scroll', keep_dialog_fixed, false);
282
            })
283
            .on('dialogclose', function() {
284
                window.removeEventListener('scroll', keep_dialog_fixed, false);
285
            })
286
            .appendTo($('body'));
287
    }
288
289
    config.height = Math.min(config.height, window.innerHeight);
290
    config.width = Math.min(config.width, window.innerHeight);
291
292
    if (url) {
293
        iframe.attr('src', url);
294
    }
295
296
    control.addClass('active');
297
    if (   control.parent().attr('role') === 'gridcell'
298
        && control.closest('.jqgrow').hasClass('ui-state-highlight') === false) {
299
        //todo: find out why the click doesn't bubble automatically
300
        control.parent().trigger('click');
301
    }
302
303
    make_dialog(dialog, config);
304
    dialog.dialog("instance").uiDialog.draggable("option", "containment", false);
305
}
306
307
function make_dialog(node, config) {
308
309
    if (!config.hasOwnProperty('buttons')) {
310
        config.buttons = [];
311
    }
312
    if (config.buttons.length === 0) {
313
        // This is not ideal, but otherwise buttons added by dialog.js are not rendered
314
        config.buttons.push({
315
            text: '...',
316
            click: function() {},
317
            css: {visibility: 'hidden'}
318
        });
319
    }
320
321
    var backup = false;
322
323
    if (typeof($.fn.popover) != 'undefined') {
324
        backup = $.button;
325
        $.widget.bridge("button", $.ui.button);
326
    }
327
328
    node
329
        .on('dialogopen', function() {
330
            // workaround for jqueryui rendering issue
331
            node.prev().find('.ui-dialog-titlebar-close').css('outline', 'none');
332
        })
333
        .dialog(config);
334
335
    if (backup) {
336
        $.button = backup;
337
    }
338
}
339