Test Setup Failed
Push — master ( ae6bbc...554531 )
by
unknown
04:38
created

  C

Complexity

Conditions 11
Paths 60

Size

Total Lines 48

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
nc 60
dl 0
loc 48
rs 5.2653
c 0
b 0
f 0
nop 1

2 Functions

Rating   Name   Duplication   Size   Complexity  
A abstract-widget.js ➔ ... ➔ mediator.once(ꞌpage:afterChangeꞌ) 0 3 1
A abstract-widget.js ➔ ... ➔ _.each 0 11 2

How to fix   Complexity   

Complexity

Complex classes like abstract-widget.js ➔ ... ➔ BaseView.extend._onJsonContentResponse 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
define(function(require) {
2
    'use strict';
3
4
    var AbstractWidgetView;
5
    var document = window.document;
6
    var $ = require('jquery');
7
    var _ = require('underscore');
8
    var tools = require('oroui/js/tools');
9
    var BaseView = require('oroui/js/app/views/base/view');
10
    var mediator = require('oroui/js/mediator');
11
    var LoadingMask = require('oroui/js/app/views/loading-mask-view');
12
    var __ = require('orotranslation/js/translator');
13
    var errorHandler = require('oroui/js/error');
14
    var messenger = require('oroui/js/messenger');
15
    require('jquery.form');
16
17
    /**
18
     * @export  oroui/js/widget/abstract-widget
19
     * @class   oroui.widget.AbstractWidgetView
20
     * @extends oroui.app.views.BaseView
21
     */
22
    AbstractWidgetView = BaseView.extend({
23
        options: {
24
            type: 'widget',
25
            actionsEl: '.widget-actions',
26
            moveAdoptedActions: true,
27
            url: false,
28
            elementFirst: true,
29
            title: '',
30
            alias: null,
31
            wid: null,
32
            actionSectionTemplate: _.template('<div data-section="<%= section %>" class="widget-actions-section"/>'),
33
            actionWrapperTemplate: _.template('<span class="action-wrapper"/>'),
34
            loadingMaskEnabled: true,
35
            loadingElement: null,
36
            container: null,
37
            submitHandler: function() {
38
                this.trigger('adoptedFormSubmit', this.form, this);
39
            },
40
            initLayoutOptions: null
41
        },
42
43
        loadingElement: null,
44
        loadingMask: null,
45
        loading: false,
46
        /**
47
         * Flag if the widget is embedded to the page
48
         * (defines life cycle of the widget)
49
         *
50
         * @type {boolean}
51
         */
52
        _isEmbedded: true,
53
54
        listen: {
55
            renderComplete: '_initSectionActions'
56
        },
57
58
        /**
59
         * @inheritDoc
60
         */
61
        constructor: function AbstractWidgetView() {
62
            AbstractWidgetView.__super__.constructor.apply(this, arguments);
63
        },
64
65
        initialize: function(options) {
66
            options = options || {};
67
            this.options = _.defaults(options, this.options);
68
            this.initializeWidget(options);
69
        },
70
71
        /**
72
         * Set widget title.
73
         *
74
         * @param {string} title
75
         */
76
        setTitle: function(title) {
0 ignored issues
show
Unused Code introduced by
The parameter title is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
77
            throw new Error('Implement setTitle');
78
        },
79
80
        /**
81
         * Get actions container element
82
         */
83
        getActionsElement: function() {
84
            throw new Error('Implement getActionsElement');
85
        },
86
87
        /**
88
         * Remove widget
89
         */
90
        remove: function() {
91
            if (!this.disposing) {
92
                // If remove method was called directly -- execute dispose first
93
                this.dispose();
94
            } else {
95
                AbstractWidgetView.__super__.remove.call(this);
96
            }
97
        },
98
99
        /**
100
         *
101
         */
102
        dispose: function() {
103
            if (this.disposed) {
104
                return;
105
            }
106
            // add flag: this is disposing process
107
            // (to prevent recursion from remove method)
108
            this.disposing = true;
109
110
            // if there's loading process -- stop it
111
            if (this.loading) {
112
                this.loading.abort();
113
                delete this.loading;
114
            }
115
116
            // call before dom will be removed
117
            this.disposePageComponents();
118
119
            // trigger all events before handlers got undelegated
120
            this.trigger('widgetRemove', this.$el);
121
            mediator.trigger('widget_remove', this.getWid());
122
            if (this.getAlias()) {
123
                mediator.trigger('widget_remove:' + this.getAlias());
124
            }
125
            this.trigger('widgetRemoved');
126
127
            AbstractWidgetView.__super__.dispose.call(this);
128
        },
129
130
        /**
131
         * Check if widget is actual. To be actual, widget should:
132
         *  - not to be disposed
133
         *  - have the element is in the DOM or have loading flag
134
         *
135
         * @returns {boolean}
136
         */
137
        isActual: function() {
138
            return !this.disposed &&
139
                (this.loading || $.contains(document.documentElement, this.el));
140
        },
141
142
        /**
143
         * Returns flag if the widget is embedded to the parent content
144
         *
145
         * @returns {boolean}
146
         */
147
        isEmbedded: function() {
148
            return this._isEmbedded;
149
        },
150
151
        /**
152
         * Initialize
153
         *
154
         * @para {Object} options Widget options
155
         */
156
        initializeWidget: function(options) {
157
            if (this.options.wid) {
158
                this._wid = this.options.wid;
159
            }
160
161
            this.on('adoptedFormSubmitClick', _.bind(this._onAdoptedFormSubmitClick, this));
162
            this.on('adoptedFormResetClick', _.bind(this._onAdoptedFormResetClick, this));
163
            this.on('adoptedFormSubmit', _.bind(this._onAdoptedFormSubmit, this));
164
            if (this.options.loadingMaskEnabled) {
165
                this.on('beforeContentLoad', _.bind(this._showLoading, this));
166
                this.on('contentLoad', _.bind(this._hideLoading, this));
167
                this.on('renderStart', _.bind(function(el) {
168
                    this.loadingElement = el;
169
                }, this));
170
            }
171
172
            this.actions = {};
173
            this.firstRun = true;
174
            this.containerFilled = false;
175
176
            this.loadingElement = $('body');
177
178
            mediator.trigger('widget_initialize', this);
179
        },
180
181
        /**
182
         * Get loading element.
183
         *
184
         * @returns {HTMLElement}
185
         * @private
186
         */
187
        _getLoadingElement: function() {
188
            var loadingElement = this.options.loadingElement || this.loadingElement;
189
            return $(loadingElement);
190
        },
191
192
        /**
193
         * Show loading indicator
194
         *
195
         * @private
196
         */
197
198
        _showLoading: function() {
199
            this.subview('loadingMask', new LoadingMask({
200
                container: this._getLoadingElement()
201
            }));
202
            this.subview('loadingMask').show();
203
        },
204
205
        /**
206
         * Hide loading indicator
207
         *
208
         * @private
209
         */
210
        _hideLoading: function() {
211
            this.removeSubview('loadingMask');
212
        },
213
214
        /**
215
         * Get unique widget identifier
216
         *
217
         * @returns {string}
218
         */
219
        getWid: function() {
220
            if (!this._wid) {
221
                this._wid = this._getUniqueIdentifier();
222
            }
223
            return this._wid;
224
        },
225
226
        /**
227
         * Get widget alias
228
         *
229
         * @returns {string|null}
230
         */
231
        getAlias: function() {
232
            return this.$el.data('alias') || this.options.alias;
233
        },
234
235
        /**
236
         * Generate unique widget identifier
237
         *
238
         * @returns {string}
239
         * @private
240
         */
241
        _getUniqueIdentifier: function() {
242
            return tools.createRandomUUID();
243
        },
244
245
        /**
246
         * Register other action elements
247
         *
248
         * @private
249
         */
250
        _initSectionActions: function() {
251
            var widget = this;
252
            var sections = this.widget.find('[data-section]');
253
            sections.each(function(i, sectionEl) {
254
                var $sectionEl = $(sectionEl);
255
                var sectionName = $sectionEl.attr('data-section');
256
                var actions = $sectionEl.find('[action-name], [data-action-name]');
257
                if ($sectionEl.attr('action-name') || $sectionEl.attr('data-action-name')) {
258
                    actions.push($sectionEl);
259
                }
260
                if (!widget.actions[sectionName]) {
261
                    widget.actions[sectionName] = {};
262
                }
263
                actions.each(function(i, actionEl) {
264
                    var $actionEl = $(actionEl);
265
                    var actionName = $actionEl.attr('action-name') || $actionEl.attr('data-action-name');
266
                    widget.actions[sectionName][actionName] = $actionEl;
267
                    widget.trigger('widget:add:action:' + sectionName + ':' + actionName, $actionEl);
268
                });
269
            });
270
        },
271
272
        /**
273
         * Convert form actions to widget actions
274
         *
275
         *  @private
276
         */
277
        _adoptWidgetActions: function() {
278
            this.actions.adopted = {};
279
            this.form = null;
280
            var adoptedActionsContainer = this._getAdoptedActionsContainer();
281
            if (adoptedActionsContainer.length > 0) {
282
                var self = this;
283
                var form = adoptedActionsContainer.closest('form');
284
                var actions = adoptedActionsContainer.find('button, input, a, [data-action-name]');
285
286
                if (form.length > 0) {
287
                    this.form = form;
288
                }
289
290
                _.each(actions, function(action, idx) {
291
                    var $action = $(action);
292
                    var actionId = $action.data('action-name') || 'adopted_action_' + idx;
293
                    switch (action.type && action.type.toLowerCase()) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
294
                        case 'submit':
295
                            var submitReplacement = $('<input type="submit"/>');
296
                            submitReplacement.css({
297
                                position: 'absolute',
298
                                left: '-9999px',
299
                                top: '-9999px',
300
                                width: '1px',
301
                                height: '1px'
302
                            });
303
                            form.prepend(submitReplacement);
304
                            actionId = 'form_submit';
305
                            break;
306
                        case 'reset':
307
                            actionId = 'form_reset';
308
                            break;
309
                    }
310
                    self.actions.adopted[actionId] = $action;
311
                });
312
                if (this.options.moveAdoptedActions) {
313
                    adoptedActionsContainer.remove();
314
                }
315
            }
316
        },
317
318
        /**
319
         * Get container with adopted form actions
320
         *
321
         * @returns {HTMLElement}
322
         * @private
323
         */
324
        _getAdoptedActionsContainer: function() {
325
            if (this.options.actionsEl !== undefined) {
326
                if (typeof this.options.actionsEl === 'string') {
327
                    return this.$el.find(this.options.actionsEl);
328
                } else if (_.isElement(this.options.actionsEl)) {
329
                    return this.options.actionsEl;
330
                }
331
            }
332
            return false;
333
        },
334
335
        /**
336
         * Handle adopted form submit button click
337
         *
338
         * @param {HTMLElement} form
339
         * @private
340
         */
341
        _onAdoptedFormSubmitClick: function(form) {
342
            form.submit();
343
        },
344
345
        /**
346
         * Handle adopted form submit
347
         *
348
         * @param {HTMLElement} form
349
         * @private
350
         */
351
        _onAdoptedFormSubmit: function(form) {
352
            if (this.loading) {
353
                return;
354
            }
355
            if (form.find('[type="file"]').length) {
356
                this.trigger('beforeContentLoad', this);
357
                form.ajaxSubmit({
358
                    data: this._getWidgetData(),
359
                    success: _.bind(this._onContentLoad, this),
360
                    errorHandlerMessage: false,
361
                    error: _.bind(this._onContentLoadFail, this)
362
                });
363
                this.loading = form.data('jqxhr');
364
            } else {
365
                var formAction = this.form.attr('action');
366
                formAction = formAction.length > 0 && formAction[0] !== '#' ? formAction : null;
367
                if (!this.options.url && formAction) {
368
                    this.options.url = formAction;
369
                }
370
                var url = formAction ? formAction : this.options.url;
371
                this.loadContent(form.serialize(), form.attr('method'), url);
372
            }
373
        },
374
375
        /**
376
         * Handle adopted form reset button click
377
         *
378
         * @param {HTMLElement} form
379
         * @private
380
         */
381
        _onAdoptedFormResetClick: function(form) {
382
            $(form).trigger('reset');
383
        },
384
385
        /**
386
         * Create container for actions section
387
         *
388
         * @param {string} section
389
         * @returns {HTMLElement}
390
         * @private
391
         */
392
        _createWidgetActionsSection: function(section) {
393
            return $(
394
                this.options.actionSectionTemplate({
395
                    section: section
396
                })
397
            );
398
        },
399
400
        /**
401
         * Append action element to sections
402
         *
403
         * @param {HTMLElement} sectionContainer
404
         * @param {HTMLElement} actionElement
405
         * @private
406
         */
407
        _appendActionElement: function(sectionContainer, actionElement) {
408
            sectionContainer.append($(this.options.actionWrapperTemplate()).append(actionElement));
409
        },
410
411
        /**
412
         * Add action element to specified section
413
         *
414
         * @param {string} key action name
415
         * @param {string} section section name
416
         * @param {HTMLElement} actionElement
417
         */
418
        addAction: function(key, section, actionElement) {
419
            if (section === undefined) {
420
                section = 'main';
421
            }
422
            if (!this.hasAction(key, section)) {
423
                if (!this.actions.hasOwnProperty(section)) {
424
                    this.actions[section] = {};
425
                }
426
                this.actions[section][key] = actionElement;
427
                var sectionContainer = this.getActionsElement().find('[data-section="' + section + '"]');
428
                if (!sectionContainer.length) {
429
                    sectionContainer = this._createWidgetActionsSection(section);
430
                    sectionContainer.appendTo(this.getActionsElement());
431
                }
432
                this._appendActionElement(sectionContainer, actionElement);
433
                this.trigger('widget:add:action:' + section + ':' + key, $(actionElement));
434
            }
435
        },
436
437
        /**
438
         * Get all registered actions
439
         *
440
         * @returns {Object}
441
         */
442
        getActions: function() {
443
            return this.actions;
444
        },
445
446
        /**
447
         * Set url
448
         *
449
         * @param {string} url
450
         */
451
        setUrl: function(url) {
452
            this.options.url = url;
453
        },
454
455
        /**
456
         * Remove action from section
457
         *
458
         * @param {string} key action name
459
         * @param {string} section section name
460
         */
461
        removeAction: function(key, section) {
462
            var self = this;
463
            function remove(actions, key) {
464
                if (_.isElement(self.actions[key])) {
465
                    self.actions[key].remove();
466
                }
467
                delete self.actions[key];
468
            }
469
            if (this.hasAction(key, section)) {
470
                if (section !== undefined) {
471
                    remove(this.actions[section], key);
472
                } else {
473
                    _.each(this.actions, function(actions, section) {
474
                        if (self.hasAction(key, section)) {
475
                            remove(actions, key);
476
                        }
477
                    });
478
                }
479
            }
480
        },
481
482
        /**
483
         * Check action availability.
484
         *
485
         * @param {string} key action name
486
         * @param {string} section section name
487
         * @returns {boolean}
488
         */
489
        hasAction: function(key, section) {
490
            if (section !== undefined) {
491
                return this.actions.hasOwnProperty(section) && this.actions[section].hasOwnProperty(key);
492
            } else {
493
                var hasAction = false;
494
                _.each(this.actions, function(actions) {
495
                    if (actions.hasOwnProperty(key)) {
496
                        hasAction = true;
497
                    }
498
                });
499
                return hasAction;
500
            }
501
        },
502
503
        /**
504
         * Check if there is at least one action.
505
         *
506
         * @param {string} section section name
507
         * @returns {boolean}
508
         */
509
        hasActions: function(section) {
510
            if (section !== undefined) {
511
                return this.actions.hasOwnProperty(section) && !_.isEmpty(this.actions[section]);
512
            } else {
513
                var hasActions = false;
514
                _.each(this.actions, function(actions) {
515
                    if (!_.isEmpty(actions)) {
516
                        hasActions = true;
517
                    }
518
                });
519
                return hasActions;
520
            }
521
        },
522
523
        /**
524
         * Get action element when after render.
525
         *
526
         * @param {string} key action name
527
         * @param {string} section section name
528
         * @param {function} callback callback method for processing action element
529
         */
530
        getAction: function(key, section, callback) {
531
            if (this.hasAction(key, section)) {
532
                var action = null;
533
                if (section !== undefined) {
534
                    action = this.actions[section][key];
535
                } else {
536
                    _.each(this.actions, function(actions) {
537
                        if (actions.hasOwnProperty(key)) {
538
                            action = actions[key];
539
                        }
540
                    });
541
                }
542
                callback(action);
543
            } else {
544
                this.once('widget:add:action:' + section + ':' + key, callback);
545
            }
546
        },
547
548
        /**
549
         * Render widget actions
550
         *
551
         * @private
552
         */
553
        _renderActions: function() {
554
            this._clearActionsContainer();
555
            var container = this.getActionsElement();
556
557
            if (container) {
558
                _.each(this.actions, function(actions, section) {
559
                    var sectionContainer = this._createWidgetActionsSection(section);
560
                    var move = section === 'adopted' ? this.options.moveAdoptedActions : true;
561
                    _.each(actions, function(action, key) {
562
                        this._initActionEvents(action);
563
                        if (move) {
564
                            this._appendActionElement(sectionContainer, action);
565
                        }
566
                        this.trigger('widget:add:action:' + section + ':' + key, $(action));
567
                    }, this);
568
                    container.append(sectionContainer);
569
                }, this);
570
            }
571
        },
572
573
        /**
574
         * Bind submit handler for widget container defined in options
575
         *
576
         * @private
577
         */
578
        _bindSubmitHandler: function() {
579
            this.$el.parent().on('submit', _.bind(function(e) {
580
                if (!e.isDefaultPrevented()) {
581
                    this.options.submitHandler.call(this);
582
                }
583
                e.preventDefault();
584
            }, this));
585
        },
586
587
        /**
588
         * Initialize adopted action event handlers
589
         *
590
         * @param {HTMLElement} action
591
         * @private
592
         */
593
        _initActionEvents: function(action) {
594
            var self = this;
595
            var type = $(action).attr('type');
596
            if (!type) {
597
                return;
598
            }
599
            switch (type.toLowerCase()) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
600
                case 'submit':
601
                    action.on('click', function() {
602
                        self.trigger('adoptedFormSubmitClick', self.form, self);
603
                        return false;
604
                    });
605
                    break;
606
607
                case 'reset':
608
                    action.on('click', function() {
609
                        self.trigger('adoptedFormResetClick', self.form, self);
610
                    });
611
                    break;
612
            }
613
        },
614
615
        /**
616
         * Clear actions container.
617
         *
618
         * @private
619
         */
620
        _clearActionsContainer: function() {
621
            var actionsEl = this.getActionsElement();
622
            if (actionsEl) {
623
                actionsEl.empty();
624
            }
625
        },
626
627
        /**
628
         * Render widget
629
         */
630
        render: function() {
631
            this._deferredRender();
632
            var loadAllowed = !this.options.elementFirst ||
633
                    (this.options.elementFirst && !this.firstRun) ||
634
                        (this.$el && this.$el.length && this.$el.html().length === 0);
635
            if (loadAllowed && this.options.url !== false) {
636
                this.loadContent();
637
            } else {
638
                this._show();
639
            }
640
            this.firstRun = false;
641
        },
642
643
        /**
644
         * Updates content of a widget.
645
         *
646
         * @param {String} content
647
         */
648
        setContent: function(content) {
649
            var widgetContent = $(content).filter('.widget-content:first');
650
651
            this.actionsEl = null;
652
            this.actions = {};
653
654
            // creating of jqUI dialog could throw exception
655
            if (widgetContent.length === 0) {
656
                throw new Error('Invalid server response: ' + content);
657
            }
658
            this.disposePageComponents();
659
            this.setElement(widgetContent);
660
            this._show();
661
        },
662
663
        /**
664
         * Load content
665
         *
666
         * @param {Object=} data
667
         * @param {string=} method
668
         * @param {string=} url
669
         */
670
        loadContent: function(data, method, url) {
671
            url = url || this.options.url;
672
            if (url === undefined || !url) {
673
                url = window.location.href;
674
            }
675
            if (this.firstRun || method === undefined || !method) {
676
                method = 'get';
677
            }
678
            var options = this.prepareContentRequestOptions(data, method, url);
679
680
            this.trigger('beforeContentLoad', this);
681
            this.loading = $.ajax(options)
682
                .done(_.bind(this._onContentLoad, this))
683
                .fail(_.bind(this._onContentLoadFail, this));
684
        },
685
686
        prepareContentRequestOptions: function(data, method, url) {
687
            var options = {
688
                url: url,
689
                type: method,
690
                data: data === void 0 ? '' : data + '&',
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
691
                errorHandlerMessage: false
692
            };
693
694
            options.data += $.param(this._getWidgetData());
695
696
            return options;
697
        },
698
699
        _getWidgetData: function() {
700
            var data = {
701
                _widgetContainer: this.options.type,
702
                _wid: this.getWid()
703
            };
704
705
            if (this.options.widgetTemplate) {
706
                data._widgetContainerTemplate = this.options.widgetTemplate;
707
            }
708
709
            return data;
710
        },
711
712
        /**
713
         * Handle content loading failure.
714
         * @private
715
         */
716
        _onContentLoadFail: function(jqxhr) {
717
            if (jqxhr.statusText === 'abort') {
718
                // content load was aborted
719
                delete this.loading;
720
                return;
721
            }
722
723
            var message = __('oro.ui.widget_loading_failed');
724
725
            if (jqxhr.status === 403) {
726
                message = __('oro.ui.forbidden_error');
727
            } else if (jqxhr.status === 404) {
728
                mediator.trigger('widget:notFound');
729
                mediator.execute('refreshPage');
730
                return;
731
            }
732
733
            var failContent = '<div class="widget-content">' +
734
                '<div class="alert alert-error">' + message + '</div>' +
735
                '</div>';
736
737
            this._onContentLoad(failContent);
738
        },
739
740
        /**
741
         * Handle loaded content.
742
         *
743
         * @param {String} content
744
         * @private
745
         */
746
        _onContentLoad: function(content) {
747
            var json = this._getJson(content);
748
749
            if (json) {
750
                content = '<div class="widget-content"></div>'; // set empty response to cover base functionality
751
            }
752
753
            delete this.loading;
754
            this.disposePageComponents();
755
            this.setContent(content, true);
756
            if (this.deferredRender) {
757
                this.deferredRender
758
                    .done(_.bind(this._triggerContentLoadEvents, this, content))
759
                    .fail(_.bind(function(error) {
760
                        if (!this.disposing && !this.disposed) {
761
                            errorHandler.showErrorInConsole(error || new Error('Widget rendering failed'));
762
                            this._triggerContentLoadEvents();
763
                        }
764
                    }, this));
765
            } else {
766
                this._triggerContentLoadEvents();
767
            }
768
769
            if (json) {
770
                this._onJsonContentResponse(json);
771
            }
772
        },
773
774
        /**
775
         * @param {String} content
776
         * @returns {json|null}
777
         * @private
778
         */
779
        _getJson: function(content) {
780
            if (_.isObject(content)) {
781
                return content; // return application/json content
782
            }
783
784
            try {
785
                return $.parseJSON(content);
786
            } catch (e) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
787
788
            return null;
789
        },
790
791
        /**
792
         * Handle returned json response
793
         *
794
         * @param {Object} content
795
         * @private
796
         */
797
        _onJsonContentResponse: function(content) {
798
            var widgetResponse = content.widget || {};
799
800
            if (_.has(widgetResponse, 'message')) {
801
                var message = widgetResponse.message;
802
803
                if (_.isString(message)) {
804
                    message = {type: 'success', text: message};
805
                }
806
807
                if (_.has(widgetResponse, 'messageAfterPageChange') && widgetResponse.messageAfterPageChange === true) {
808
                    mediator.once('page:afterChange', function() {
809
                        messenger.notificationFlashMessage(message.type, message.text);
810
                    });
811
                } else {
812
                    messenger.notificationFlashMessage(message.type, message.text);
813
                }
814
            }
815
816
            if (_.has(widgetResponse, 'trigger')) {
817
                var events = widgetResponse.trigger;
818
819
                if (!_.isObject(events)) {
820
                    events = [events];
821
                }
822
823
                _.each(events, function(event) {
824
                    var eventBroker = this._getEventBroker(event);
825
                    var eventFunction = this._getEventFunction(event);
826
827
                    if (_.isObject(event)) {
828
                        var args = [event.name].concat(event.args);
829
                        eventBroker[eventFunction].apply(eventBroker, args);
830
                    } else {
831
                        eventBroker[eventFunction](event);
832
                    }
833
                }, this);
834
            }
835
836
            if (_.has(widgetResponse, 'triggerSuccess') && widgetResponse.triggerSuccess) {
837
                mediator.trigger('widget_success:' + this.getAlias());
838
                mediator.trigger('widget_success:' + this.getWid());
839
            }
840
841
            if (_.has(widgetResponse, 'remove') && widgetResponse.remove) {
842
                this.remove();
843
            }
844
        },
845
846
        _getEventBroker: function(event) {
847
            return event.eventBroker === 'widget' ? this : mediator;
848
        },
849
850
        _getEventFunction: function(event) {
851
            return event.eventFunction === 'execute' ? 'execute' : 'trigger';
852
        },
853
854
        _triggerContentLoadEvents: function(content) {
855
            this.trigger('contentLoad', content, this);
856
            mediator.trigger('widget:contentLoad', this.widget);
857
            mediator.trigger('layout:adjustHeight');
858
        },
859
860
        /**
861
         * @inheritDoc
862
         */
863
        getLayoutElement: function() {
864
            return this.widget;
865
        },
866
867
        /**
868
         * Show widget content
869
         *
870
         * @private
871
         */
872
        _show: function() {
873
            this._adoptWidgetActions();
874
            this.trigger('renderStart', this.$el, this);
875
            this.show();
876
            this._renderInContainer();
877
            this.trigger('renderComplete', this.$el, this);
878
            this.getLayoutElement().attr('data-layout', 'separate');
879
            this.initLayout(this.options.initLayoutOptions || {})
880
                .done(_.bind(this._afterLayoutInit, this));
881
        },
882
883
        _afterLayoutInit: function() {
884
            if (this.disposed) {
885
                return;
886
            }
887
            if (this.deferredRender) {
888
                this.deferredRender.done(_.bind(this._renderHandler, this));
889
                this._resolveDeferredRender();
890
            } else {
891
                this._renderHandler();
892
            }
893
        },
894
895
        _renderHandler: function() {
896
            this.widget.removeClass('invisible');
897
            this.trigger('widgetReady', this);
898
        },
899
900
        /**
901
         * General implementation of show logic.
902
         */
903
        show: function() {
904
            this.setWidToElement(this.$el);
905
            this._renderActions();
906
            this._bindSubmitHandler();
907
            this.trigger('widgetRender', this.$el, this);
908
            mediator.trigger('widget:render:' + this.getWid(), this.$el, this);
909
        },
910
911
        _renderInContainer: function() {
912
            if (!this.containerFilled && this.options.container) {
913
                this.widget.addClass('invisible');
914
                $(this.options.container).append(this.widget);
915
                this.containerFilled = true;
916
            }
917
        },
918
919
        /**
920
         * Add data-wid attribute to given element.
921
         *
922
         * @param {HTMLElement} el
923
         */
924
        setWidToElement: function(el) {
925
            el.attr('data-wid', this.getWid());
926
        }
927
    });
928
929
    return AbstractWidgetView;
930
});
931