Test Setup Failed
Push — master ( d00a46...d73e35 )
by
unknown
03:25
created

  A

Complexity

Conditions 2
Paths 5

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 5
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
nop 0

1 Function

Rating   Name   Duplication   Size   Complexity  
A product-variant-field-component.js ➔ ... ➔ _.bind 0 14 1
1
define(function(require) {
2
    'use strict';
3
4
    var ProductVariantFieldComponent;
5
    var _ = require('underscore');
6
    var $ = require('jquery');
7
    var ViewComponent = require('oroui/js/app/components/view-component');
8
    var error = require('oroui/js/error');
9
10
    ProductVariantFieldComponent = ViewComponent.extend({
11
12
        /**
13
         * @property {Object}
14
         */
15
        options: {
16
            simpleProductVariants: []
17
        },
18
19
        /**
20
         * Source DOM element
21
         */
22
        $el: null,
23
24
        /**
25
         * All options without default disabled
26
         * @property {Array}
27
         */
28
        filteredOptions: [],
29
30
        /**
31
         * Filtered options after resolving
32
         */
33
        _filtered: null,
34
35
        /**
36
         * Hierarchy stack of product variants
37
         */
38
        _hierarchy: [],
39
40
        /**
41
         * Current state
42
         */
43
        state: null,
44
45
        /**
46
         * {@inheritDoc}
47
         */
48
        initialize: function(options) {
49
            this.options = _.defaults(options || {}, this.options);
50
            ProductVariantFieldComponent.__super__.initialize.apply(this, arguments);
51
52
            // _sourceElement is a form element which contains selects
53
            this.$el = this.options._sourceElement;
54
55
            this._prepareProductVariants();
56
57
            this.deferredInit.done(_.bind(this._initVariantInstances, this));
58
        },
59
60
        /**
61
         * Set state
62
         *
63
         * @param {string} name
64
         * @param {object} value
65
         * @returns {*}
66
         */
67
        setState: function(name, value) {
68
            if (_.isUndefined(value)) {
69
                return error.showErrorInConsole('The value should be defined');
70
            }
71
72
            if (!this.state) {
73
                this.state = {};
74
            }
75
76
            this.state[name] = value;
77
78
            return this.state;
79
        },
80
81
        /**
82
         * Get current state by property
83
         *
84
         * @param {String} name
85
         * @returns {null}
86
         */
87
        getState: function(name) {
88
            return name ? this.state[name] : this.state;
89
        },
90
91
        /**
92
         * Trigger select2 to update view
93
         */
94
        updateFields: function() {
95
            this.$el.find('select').each(_.bind(function(index, select) {
96
                if (this._filtered.indexOf($(select).val()) === -1) {
97
                    $(select).val('');
98
                    this.setState(this._extractName($(select).data('name')), null);
99
                }
100
                $(select).trigger('change.select2');
101
            }, this));
102
        },
103
104
        dispose: function() {
105
            if (this.disposed) {
106
                return;
107
            }
108
109
            this.$el.off();
110
111
            delete this._filtered;
112
            delete this._hierarchy;
113
            delete this.state;
114
            delete this.filteredOptions;
115
116
            ProductVariantFieldComponent.__super__.dispose.apply(this);
117
        },
118
119
        /**
120
         * Initialize variants
121
         *
122
         * @private
123
         */
124
        _initVariantInstances: function() {
125
            var onChangeHandler = _.bind(this._onVariantFieldChange, this, this.options.simpleProductVariants);
126
127
            if (this.$el.find('select').length) {
128
                this.$el.find('select').each(_.bind(function(index, select) {
129
                    var $select = $(select);
130
                    var normalizeName = this._extractName($select.data('name'));
131
132
                    this.filteredOptions = this.filteredOptions.concat(
133
                        $select.find('option').get().filter(_.bind(function(option) {
134
                            option.value = option.value !== '' ? normalizeName + '_' + option.value : '';
135
                            return !option.disabled && option.value !== '';
136
                        }, this))
137
                    );
138
139
                    this._appendToHierarchy(normalizeName);
140
                    this.setState(normalizeName, $select.val());
141
                }, this));
142
            }
143
144
            this._resolveVariantFieldsChain(this.options.simpleProductVariants);
145
            this.$el.on('change', 'select', onChangeHandler);
146
        },
147
148
        /**
149
         * Fix case where attributes similar value make attribute unique value
150
         *
151
         * @private
152
         */
153
        _prepareProductVariants: function() {
154
            this.options.simpleProductVariants = _.mapObject(this.options.simpleProductVariants, function(variant) {
155
                return _.reduce(variant, function(memo, attr, key) {
156
                    memo[this._extractName(key)] = (
157
                        this._extractName(key) + '_' + this._normalizeBool(attr)
158
                    ).toLowerCase();
159
                    return memo;
160
                }, {}, this);
161
            }, this);
162
        },
163
164
        /**
165
         * Append new item to hierarchy stack
166
         *
167
         * @param {object} newOne
168
         * @returns {null}
169
         * @private
170
         */
171
        _appendToHierarchy: function(newOne) {
172
            if (!_.isString(newOne)) {
173
                return error.showErrorInConsole(newOne + ' should be string');
174
            }
175
176
            if (this._hierarchy.indexOf(newOne) === -1) {
177
                this._hierarchy.push(newOne);
178
            } else {
179
                return error.showErrorInConsole('Item: ' + newOne + ' is already exist!');
180
            }
181
182
            return this._hierarchy;
183
        },
184
185
        /**
186
         * onChange handler for select variant fields
187
         *
188
         * @param {object} simpleProductVariants
189
         * @param {object} event
190
         * @private
191
         */
192
        _onVariantFieldChange: function(simpleProductVariants, event) {
193
            var $target = $(event.target);
194
195
            this.setState(this._extractName($target.data('name')), $target.val());
196
            this._resolveVariantFieldsChain(simpleProductVariants);
197
        },
198
199
        /**
200
         * Resolve field hierarchy depends selected options
201
         *
202
         * @param {Object} simpleProductVariants
203
         * @private
204
         */
205
        _resolveVariantFieldsChain: function(simpleProductVariants) {
206
            this._filtered = this._resolveHierarchy(simpleProductVariants);
207
208
            this.filteredOptions.forEach(_.bind(function(field) {
209
                field.disabled = _.indexOf(this._filtered, field.value) === -1;
210
            }, this));
211
212
            this._updateProduct();
213
            this.updateFields();
214
        },
215
216
        /**
217
         *
218
         * @param {Object} simpleProductVariants
219
         * @returns {Array}
220
         * @private
221
         */
222
        _resolveHierarchy: function(simpleProductVariants) {
223
            var result = [];
224
225
            this._hierarchy.forEach(_.bind(function(field, index) {
226
                var parentField = this._hierarchy[index - 1];
227
228
                simpleProductVariants = _.isUndefined(parentField) ?
229
                    simpleProductVariants :
230
                    _.where(simpleProductVariants, this._prepareFoundKeyValue(parentField));
231
232
                result = result.concat(_.uniq(_.pluck(simpleProductVariants, field)));
233
            }, this));
234
235
            return result;
236
        },
237
238
        _prepareFoundKeyValue: function(value) {
239
            var result = {};
240
            result[value] = this.getState(value);
241
242
            return result;
243
        },
244
245
        /**
246
         * Update product model in view
247
         *
248
         * @private
249
         */
250
        _updateProduct: function() {
251
            var variants = this.options.simpleProductVariants;
252
            this.foundProductId = null;
253
254
            for (var variant in variants) {
255
                if (variants.hasOwnProperty(variant) && _.isEqual(this.getState(), variants[variant])) {
256
                    this.foundProductId = variant;
257
                    break;
258
                }
259
            }
260
261
            this.view.updateProductInfo(this.foundProductId);
262
        },
263
264
        /**
265
         * Helper method for normalize field name from 'form__name' to 'Name'
266
         *
267
         * @param {String} name
268
         * @returns {string}
269
         * @private
270
         */
271
        _extractName: function(name) {
272
            name = name.toLowerCase().split('__').slice(-1)[0];
273
            name = name.replace(/[-_]/g, '');
274
            return name;
275
        },
276
277
        /**
278
         * Convert from "true" or "false" to "1" and "0"
279
         *
280
         * @param {boolean} value
281
         * @returns {number}
282
         * @private
283
         */
284
        _normalizeBool: function(value) {
285
            return _.isBoolean(value) ? +value : value;
286
        }
287
    });
288
289
    return ProductVariantFieldComponent;
290
});
291