src/Oro/Bundle/OrderBundle/Resources/public/js/app/views/discount-collection-view.js   B
last analyzed

Complexity

Total Complexity 40
Complexity/F 1.54

Size

Lines of Code 325
Function Count 26

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
wmc 40
nc 4
mnd 2
bc 41
fnc 26
dl 0
loc 325
rs 8.2608
bpm 1.5769
cpm 1.5384
noi 0
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like src/Oro/Bundle/OrderBundle/Resources/public/js/app/views/discount-collection-view.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
define(function(require) {
2
    'use strict';
3
4
    var DiscountCollectionView;
5
    var $ = require('jquery');
6
    var _ = require('underscore');
7
    var mediator = require('oroui/js/mediator');
8
    var BaseView = require('oroui/js/app/views/base/view');
9
    var tools = require('oroui/js/tools');
10
    var LoadingMask = require('oroui/js/app/views/loading-mask-view');
11
12
    DiscountCollectionView = BaseView.extend({
13
        /**
14
         * @property {Object}
15
         */
16
        options: {
17
            discountType: null,
18
            totalType: null,
19
            dialogAlias: 'add-order-discount-dialog',
20
            percentType: null,
21
            selectors: {
22
                discountsSumSelector: '[data-ftid=oro_order_type_discountsSum]',
23
                deleteButton: 'a[data-role="remove"]',
24
                hiddenCollection: '[data-role="hidden-collection"]',
25
                hiddenInputsForIndex: 'input[name*="[INDEX]"]',
26
                parentForLoadingMask: '.responsive-section',
27
                formFields: {
28
                    description: '[data-role=description]',
29
                    type: '[data-role=type]',
30
                    percent: '[data-role=percent]',
31
                    amount: '[data-role=amount]',
32
                    value: '[data-role=value]'
33
                }
34
            }
35
        },
36
37
        /**
38
         * @inheritDoc
39
         */
40
        constructor: function DiscountCollectionView(options) {
41
            this.options = $.extend(true, {}, this.options, options || {});
42
            DiscountCollectionView.__super__.constructor.call(this, options);
43
        },
44
45
        /**
46
         * @inheritDoc
47
         */
48
        events: function() {
49
            var events = {};
50
            events['click ' + this.options.selectors.deleteButton] = 'onDeleteClick';
51
52
            return events;
53
        },
54
55
        /**
56
         * @inheritDoc
57
         */
58
        initialize: function() {
59
            var handlers = {};
60
            handlers['totals:update'] = this.updateSumAndValidators;
61
            handlers.widget_initialize = this.attachDialogListeners;
62
            handlers['entry-point:order:load'] = this.refreshCollectionBlock;
63
64
            this.listenTo(mediator, handlers);
65
        },
66
67
        /**
68
         * @param {Object} response
69
         */
70
        refreshCollectionBlock: function(response) {
71
            if ('discounts' in response) {
72
                var collectionBlockHtml = $(response.discounts).html();
73
                this.$el.html(collectionBlockHtml);
74
                this.$el.trigger('content:changed');
75
            }
76
            this._hideLoading();
77
        },
78
79
        /**
80
         * @param {Object} subtotals
81
         */
82
        updateSumAndValidators: function(subtotals) {
83
            var $discountsSumElement = this.$el.closest('form').find(this.options.selectors.discountsSumSelector);
84
            var dataValidation = $discountsSumElement.data('validation');
85
            var discountsSum = 0;
86
            var total = 0;
87
88
            var self = this;
89
            _.each(subtotals.subtotals, function(subtotal) {
90
                if (subtotal.type === self.options.discountType) {
91
                    discountsSum += subtotal.amount;
92
                }
93
94
                if (subtotal.type === self.options.totalType) {
95
                    total = subtotal.amount;
96
                }
97
            });
98
99
            $discountsSumElement.val(discountsSum);
100
101
            if (dataValidation && !_.isEmpty(dataValidation.Range)) {
102
                dataValidation.Range.max = total;
103
            }
104
105
            var validator = $($discountsSumElement.closest('form')).validate();
106
            if (validator) {
107
                validator.element($discountsSumElement);
108
            }
109
        },
110
111
        /**
112
         * @param {Object} widget
113
         */
114
        attachDialogListeners: function(widget) {
115
            var self = this;
116
            if ('add-order-discount-dialog' === widget.getAlias()) {
117
                widget.on('contentLoad', function() {
118
                    widget.$el.on('submit', _.bind(self.onAddSubmit, self, widget));
119
                });
120
            } else if ('edit-order-discount-dialog' === widget.getAlias()) {
121
                widget.on('contentLoad', function() {
122
                    self._populateDialogForm(this);
123
                    widget.$el.on('submit', _.bind(self.onEditSubmit, self, widget));
124
                });
125
            }
126
        },
127
128
        /**
129
         * Handler of "Add" dialog "submit" event.
130
         *
131
         * @param {Object} widget
132
         * @param {Event} event
133
         */
134
        onAddSubmit: function(widget, event) {
135
            this._createInputsFromSubmission(widget.form);
136
            this._showLoading();
137
            widget.remove();
138
            mediator.trigger('entry-point:order:trigger');
139
            event.preventDefault();
140
        },
141
142
        /**
143
         * Handler of "Edit" dialog "submit" event.
144
         *
145
         * @param {Object} widget
146
         * @param {Event} event
147
         */
148
        onEditSubmit: function(widget, event) {
149
            this._updateInputsFromSubmission(widget);
150
            this._showLoading();
151
            widget.remove();
152
            mediator.trigger('entry-point:order:trigger');
153
            event.preventDefault();
154
        },
155
156
        /**
157
         * Handler of click on "delete" action
158
         *
159
         * @param {Event} event
160
         */
161
        onDeleteClick: function(event) {
162
            var collectionElementIndex = $(event.target).data('element-index');
163
            this._getSelectedHiddenInputs(collectionElementIndex).remove();
164
            this._showLoading();
165
            mediator.trigger('entry-point:order:trigger');
166
        },
167
168
        /**
169
         * Set values from submission to the corresponding fields in $newInputs.
170
         *
171
         * @param {HTMLElement} form
172
         * @param {jQuery} $newInputs
173
         * @private
174
         */
175
        _populateCollectionInputsWithSubmission: function(form, $newInputs) {
176
            _.each(this.options.selectors.formFields, _.bind(function(fieldSelector, fieldType) {
177
                if ('value' !== fieldType) {
178
                    var submissionInputVal = $(fieldSelector, form).val();
179
                    $newInputs.filter(fieldSelector).attr('value', submissionInputVal);
180
                }
181
            }, this), form);
182
        },
183
184
        /**
185
         * Create inputs in hidden collection based on the submission from dialog form.
186
         *
187
         * @param {HTMLElement} form
188
         * @private
189
         */
190
        _createInputsFromSubmission: function(form) {
191
            var $newInputs = this._createNewHiddenCollectionInputs();
192
            this._populateCollectionInputsWithSubmission(form, $newInputs);
193
            this.$(this.options.selectors.hiddenCollection).append($newInputs);
194
        },
195
196
        /**
197
         * Update inputs in hidden collection based on the submission from dialog form.
198
         *
199
         * @param {Object} widget
200
         * @private
201
         */
202
        _updateInputsFromSubmission: function(widget) {
203
            var $hiddenInputs = this._getSelectedHiddenInputs(widget.options.dialogOptions.collectionElementIndex);
204
            this._populateCollectionInputsWithSubmission(widget.form, $hiddenInputs);
205
        },
206
207
        /**
208
         * Based on the form's prototype and last index create inputs for new row.
209
         *
210
         * @returns {jQuery}
211
         * @private
212
         */
213
        _createNewHiddenCollectionInputs: function() {
214
            var inputsPrototypeString = this.$(this.options.selectors.hiddenCollection).data('prototype');
215
            var prototypeName = this.$(this.options.selectors.hiddenCollection).data('prototype-name');
216
            var lastIndex = this.$(this.options.selectors.hiddenCollection).data('last-index');
217
            var newInputsHtml = inputsPrototypeString.replace(tools.safeRegExp(prototypeName, 'ig'), lastIndex);
218
219
            return $(newInputsHtml);
220
        },
221
222
        /**
223
         * Based on the selected element's info populate dialog form's inputs.
224
         *
225
         * @param {Object} widget
226
         * @private
227
         */
228
        _populateDialogForm: function(widget) {
229
            var $hiddenInputs = this._getSelectedHiddenInputs(widget.options.dialogOptions.collectionElementIndex);
230
            this._setDialogFormInputs($hiddenInputs, widget);
231
            this._triggerFormValueWidgetRefresh(widget);
232
        },
233
234
        /**
235
         * Based on the passed element index get related row's inputs.
236
         *
237
         * @param {int} collectionElementIndex
238
         * @returns {jQuery}
239
         * @private
240
         */
241
        _getSelectedHiddenInputs: function(collectionElementIndex) {
242
            var inputsSelector = this.options.selectors.hiddenInputsForIndex.replace(
243
                tools.safeRegExp('INDEX', 'ig'),
244
                collectionElementIndex
245
            );
246
247
            return this.$el.find(inputsSelector);
248
        },
249
250
        /**
251
         * Set dialog form inputs based on the received $hiddenInputs, for editing.
252
         *
253
         * @param {jQuery} $hiddenInputs
254
         * @param {Object} widget
255
         * @private
256
         */
257
        _setDialogFormInputs: function($hiddenInputs, widget) {
258
            _.each(this.options.selectors.formFields, _.bind(function(fieldSelector, fieldType) {
259
                var hiddenInputVal;
260
                if ('value' === fieldType) {
261
                    var selectedType = widget.$el
262
                        .find(this.options.selectors.formFields.type).val();
263
                    if (this.options.percentType === selectedType) {
264
                        hiddenInputVal = $($hiddenInputs)
265
                            .filter(this.options.selectors.formFields.percent).val();
266
                    } else {
267
                        hiddenInputVal = $($hiddenInputs)
268
                            .filter(this.options.selectors.formFields.amount).val();
269
                    }
270
                    widget.$el.find(fieldSelector).val(hiddenInputVal);
271
                } else {
272
                    hiddenInputVal = $($hiddenInputs).filter(fieldSelector).val();
273
                    widget.$el.find(fieldSelector).val(hiddenInputVal);
274
                }
275
            }, this), widget);
276
        },
277
278
        /**
279
         * Trigger refresh of form inputs widget, that listen to "change".
280
         *
281
         * @param {Object} widget
282
         * @private
283
         */
284
        _triggerFormValueWidgetRefresh: function(widget) {
285
            widget.$el.find(this.options.selectors.formFields.type).trigger('change');
286
        },
287
288
        /**
289
         * @private
290
         */
291
        _showLoading: function() {
292
            this._ensureLoadingMaskLoaded();
293
294
            if (!this.subview('loadingMask').isShown()) {
295
                this.subview('loadingMask').show();
296
            }
297
        },
298
299
        /**
300
         * @private
301
         */
302
        _hideLoading: function() {
303
            this._ensureLoadingMaskLoaded();
304
305
            if (this.subview('loadingMask').isShown()) {
306
                this.subview('loadingMask').hide();
307
            }
308
        },
309
310
        /**
311
         * Add subview with loadingMask if not already.
312
         *
313
         * @private
314
         */
315
        _ensureLoadingMaskLoaded: function() {
316
            if (!this.subview('loadingMask')) {
317
                this.subview('loadingMask', new LoadingMask({
318
                    container: this.$el.parents(this.options.selectors.parentForLoadingMask)
319
                }));
320
            }
321
        }
322
    });
323
324
    return DiscountCollectionView;
325
});
326