1
|
|
|
define(function(require) { |
2
|
|
|
'use strict'; |
3
|
|
|
|
4
|
|
|
var ProductCollectionApplyQueryComponent; |
5
|
|
|
var BaseComponent = require('oroui/js/app/components/base/component'); |
6
|
|
|
var StandardConfirmation = require('oroui/js/standart-confirmation'); |
7
|
|
|
var __ = require('orotranslation/js/translator'); |
8
|
|
|
var _ = require('underscore'); |
9
|
|
|
var $ = require('jquery'); |
10
|
|
|
var mediator = require('oroui/js/mediator'); |
11
|
|
|
var InclusionExclusionSubComponent = |
12
|
|
|
require('oroproduct/js/app/components/product-collection-inclusion-exclusion-subcomponent'); |
13
|
|
|
var SelectedProductGridSubComponent = |
14
|
|
|
require('oroproduct/js/app/components/product-collection-selected-product-grid-subcomponent'); |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Perform synchronization between segment definition filters block and grid. By click on "apply the query" button |
18
|
|
|
* will apply the definition filters to the related grid. |
19
|
|
|
*/ |
20
|
|
|
ProductCollectionApplyQueryComponent = BaseComponent.extend({ |
21
|
|
|
/** |
22
|
|
|
* @property {Object} |
23
|
|
|
*/ |
24
|
|
|
options: { |
25
|
|
|
segmentDefinitionSelectorTemplate: 'input[name="%s"]', |
26
|
|
|
controlsBlockAlias: null, |
27
|
|
|
gridName: null, |
28
|
|
|
scope: null, |
29
|
|
|
excludedControlsBlockAlias: null, |
30
|
|
|
includedControlsBlockAlias: null, |
31
|
|
|
excludedProductsGridName: null, |
32
|
|
|
includedProductsGridName: null, |
33
|
|
|
selectors: { |
34
|
|
|
reset: null, |
35
|
|
|
apply: null, |
36
|
|
|
included: null, |
37
|
|
|
excluded: null |
38
|
|
|
} |
39
|
|
|
}, |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @property {Object} |
43
|
|
|
*/ |
44
|
|
|
requiredOptions: [ |
45
|
|
|
'segmentDefinitionFieldName', |
46
|
|
|
'controlsBlockAlias', |
47
|
|
|
'gridName', |
48
|
|
|
'scope', |
49
|
|
|
'excludedControlsBlockAlias', |
50
|
|
|
'includedControlsBlockAlias', |
51
|
|
|
'excludedProductsGridName', |
52
|
|
|
'includedProductsGridName' |
53
|
|
|
], |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @property string|null |
57
|
|
|
*/ |
58
|
|
|
initialDefinitionState: null, |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @property string|null |
62
|
|
|
*/ |
63
|
|
|
initialIncluded: null, |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @property string|null |
67
|
|
|
*/ |
68
|
|
|
initialExcluded: null, |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @property string|null |
72
|
|
|
*/ |
73
|
|
|
currentDefinitionState: null, |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @property {Boolean} |
77
|
|
|
*/ |
78
|
|
|
confirmed: false, |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @property {Boolean} |
82
|
|
|
*/ |
83
|
|
|
confirmModalInitialized: false, |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @property {jQuery.Element} |
87
|
|
|
*/ |
88
|
|
|
$form: null, |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @property {jQuery.Element} |
92
|
|
|
*/ |
93
|
|
|
$included: null, |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @property {jQuery.Element} |
97
|
|
|
*/ |
98
|
|
|
$excluded: null, |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @property {String} |
102
|
|
|
*/ |
103
|
|
|
namespace: null, |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @property {Object} |
107
|
|
|
*/ |
108
|
|
|
inclusionExclusionSubComponent: null, |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @property {Object} |
112
|
|
|
*/ |
113
|
|
|
selectedProductGridSubComponent: null, |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @property {String} |
117
|
|
|
*/ |
118
|
|
|
applyQueryEventName: null, |
119
|
|
|
|
120
|
|
|
/** |
121
|
|
|
* @inheritDoc |
122
|
|
|
*/ |
123
|
|
|
constructor: function ProductCollectionApplyQueryComponent() { |
124
|
|
|
ProductCollectionApplyQueryComponent.__super__.constructor.apply(this, arguments); |
125
|
|
|
}, |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @inheritDoc |
129
|
|
|
*/ |
130
|
|
|
initialize: function(options) { |
131
|
|
|
this.options = $.extend(true, {}, this.options, options || {}); |
132
|
|
|
|
133
|
|
|
this._checkOptions(); |
134
|
|
|
|
135
|
|
|
this.$included = this.options._sourceElement.find(this.options.selectors.included); |
136
|
|
|
this.$excluded = this.options._sourceElement.find(this.options.selectors.excluded); |
137
|
|
|
this.$form = this.options._sourceElement.closest('form'); |
138
|
|
|
|
139
|
|
|
this.options._sourceElement |
140
|
|
|
.on('click', this.options.selectors.apply, _.bind(this.onApplyQuery, this)) |
141
|
|
|
.on('click', this.options.selectors.reset, _.bind(this.onReset, this)) |
142
|
|
|
.on('query-designer:validate:not-blank-filters', _.bind(this.onFiltersValidate, this)); |
143
|
|
|
|
144
|
|
|
this.initialDefinitionState = this._getSegmentDefinition(); |
145
|
|
|
this.initialIncluded = this.$included.val(); |
146
|
|
|
this.initialExcluded = this.$excluded.val(); |
147
|
|
|
|
148
|
|
|
if (this.initialDefinitionState !== null && this.initialDefinitionState !== '') { |
149
|
|
|
this.currentDefinitionState = this.initialDefinitionState; |
150
|
|
|
mediator.on('grid-sidebar:load:' + this.options.controlsBlockAlias, this._applyQuery, this); |
151
|
|
|
} |
152
|
|
|
this.$form.on('submit' + this.eventNamespace(), _.bind(this.onSubmit, this)); |
153
|
|
|
|
154
|
|
|
this.applyQueryEventName = 'productCollection:applyQuery:' + this.eventNamespace(); |
155
|
|
|
mediator.on(this.applyQueryEventName, _.bind(this.applyQuery, this)); |
156
|
|
|
this._initializeInclusionExclusionSubComponent(); |
157
|
|
|
this._initializeSelectedProductGridsSubComponent(); |
158
|
|
|
|
159
|
|
|
this._enableHiddenFieldValidation(); |
160
|
|
|
}, |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* @return {String} |
164
|
|
|
*/ |
165
|
|
|
eventNamespace: function() { |
166
|
|
|
if (this.namespace === null) { |
167
|
|
|
this.namespace = _.uniqueId('.applyQuery'); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
return this.namespace; |
171
|
|
|
}, |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* @param {jQuery.Event} event |
175
|
|
|
* @return {Boolean} |
176
|
|
|
*/ |
177
|
|
|
onSubmit: function(event) { |
178
|
|
|
if (!$(event.target).valid()) { |
179
|
|
|
return true; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
if (!this._isCurrentDefinitionStateChange()) { |
183
|
|
|
return true; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
if (this._isConfirmed()) { |
187
|
|
|
return true; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
event.stopImmediatePropagation(); |
191
|
|
|
this._showConfirmModal(); |
192
|
|
|
|
193
|
|
|
return false; |
194
|
|
|
}, |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* @param {jQuery.Event} e |
198
|
|
|
*/ |
199
|
|
|
onApplyQuery: function(e) { |
200
|
|
|
e.preventDefault(); |
201
|
|
|
if (this._isConditionBuilderValid()) { |
202
|
|
|
mediator.trigger(this.applyQueryEventName); |
203
|
|
|
} |
204
|
|
|
}, |
205
|
|
|
|
206
|
|
|
applyQuery: function() { |
207
|
|
|
this.currentDefinitionState = this._getSegmentDefinition(); |
208
|
|
|
this._applyQuery(true); |
209
|
|
|
}, |
210
|
|
|
|
211
|
|
|
onConfirmModalOk: function() { |
212
|
|
|
this._setConfirmed(); |
213
|
|
|
this.$form.trigger('submit'); |
214
|
|
|
}, |
215
|
|
|
|
216
|
|
|
onReset: function(e) { |
217
|
|
|
var filters = this.initialDefinitionState ? JSON.parse(this.initialDefinitionState).filters : []; |
218
|
|
|
this.updateSegmentDefinitionValue('filters', filters); |
219
|
|
|
this.currentDefinitionState = this.initialDefinitionState; |
220
|
|
|
this.$included.val(this.initialIncluded).trigger('change'); |
221
|
|
|
this.$excluded.val(this.initialExcluded).trigger('change'); |
222
|
|
|
this.onApplyQuery(e); |
223
|
|
|
}, |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* @param {jQuery.Event} e |
227
|
|
|
* @param {Object} data |
228
|
|
|
*/ |
229
|
|
|
onFiltersValidate: function(e, data) { |
230
|
|
|
var filters = this.fetchSegmentDefinitionValue('filters'); |
231
|
|
|
if (!_.isEmpty(filters) || this.$included.val()) { |
232
|
|
|
data.result = true; |
233
|
|
|
} |
234
|
|
|
}, |
235
|
|
|
|
236
|
|
|
_checkOptions: function() { |
237
|
|
|
var requiredMissed = this.requiredOptions.filter(_.bind(function(option) { |
238
|
|
|
return _.isUndefined(this.options[option]); |
239
|
|
|
}, this)); |
240
|
|
|
if (requiredMissed.length) { |
241
|
|
|
throw new TypeError('Missing required option(s): ' + requiredMissed.join(', ')); |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
var requiredSelectors = []; |
245
|
|
|
_.each(this.options.selectors, function(selector, selectorName) { |
246
|
|
|
if (!selector) { |
247
|
|
|
requiredSelectors.push(selectorName); |
248
|
|
|
} |
249
|
|
|
}); |
250
|
|
|
if (requiredSelectors.length) { |
251
|
|
|
throw new TypeError('Missing required selectors(s): ' + requiredSelectors.join(', ')); |
252
|
|
|
} |
253
|
|
|
}, |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* @private |
257
|
|
|
*/ |
258
|
|
|
_applyQuery: function(reload) { |
259
|
|
|
var parameters = { |
260
|
|
|
updateUrl: false, |
261
|
|
|
reload: reload, |
262
|
|
|
params: {} |
263
|
|
|
}; |
264
|
|
|
|
265
|
|
|
parameters.params['sd_' + this.options.gridName] = this.currentDefinitionState; |
266
|
|
|
parameters.params['sd_' + this.options.gridName + ':incl'] = this.$included.val(); |
267
|
|
|
parameters.params['sd_' + this.options.gridName + ':excl'] = this.$excluded.val(); |
268
|
|
|
|
269
|
|
|
mediator.trigger('grid-sidebar:change:' + this.options.controlsBlockAlias, parameters); |
270
|
|
|
}, |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* @return {String} |
274
|
|
|
* @private |
275
|
|
|
*/ |
276
|
|
|
_getSegmentDefinition: function() { |
277
|
|
|
return this._getSegmentDefinitionInput().val(); |
278
|
|
|
}, |
279
|
|
|
|
280
|
|
|
_getSegmentDefinitionInput: function() { |
281
|
|
|
var name = this.options.segmentDefinitionFieldName; |
282
|
|
|
return $(this.options.segmentDefinitionSelectorTemplate.replace('%s', name)); |
283
|
|
|
}, |
284
|
|
|
|
285
|
|
|
/** |
286
|
|
|
* Loads data from the segment definition input |
287
|
|
|
* |
288
|
|
|
* @param {string=} key name of data branch |
289
|
|
|
*/ |
290
|
|
|
fetchSegmentDefinitionValue: function(key) { |
291
|
|
|
var data = {}; |
292
|
|
|
var json = this._getSegmentDefinitionInput().val(); |
293
|
|
|
if (json) { |
294
|
|
|
try { |
295
|
|
|
data = JSON.parse(json); |
296
|
|
|
} catch (e) { |
297
|
|
|
return undefined; |
298
|
|
|
} |
299
|
|
|
} |
300
|
|
|
return key ? data[key] : data; |
301
|
|
|
}, |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Saves data to the segment definition input |
305
|
|
|
* |
306
|
|
|
* @param {Object|string} value data if single argument is passed or key name of data branch |
307
|
|
|
* @param {Object=} value data for data branch |
|
|
|
|
308
|
|
|
*/ |
309
|
|
|
updateSegmentDefinitionValue: function(value) { |
310
|
|
|
var key; |
311
|
|
|
var data = this.fetchSegmentDefinitionValue(); |
312
|
|
|
if (arguments.length === 2) { |
313
|
|
|
key = value; |
314
|
|
|
value = arguments[1]; |
315
|
|
|
data[key] = value; |
316
|
|
|
} else { |
317
|
|
|
data = value; |
318
|
|
|
} |
319
|
|
|
this._getSegmentDefinitionInput().val(JSON.stringify(data)).trigger('change'); |
320
|
|
|
}, |
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* @return {Boolean} |
324
|
|
|
* @private |
325
|
|
|
*/ |
326
|
|
|
_isCurrentDefinitionStateChange: function() { |
327
|
|
|
return this.currentDefinitionState !== this._getSegmentDefinition(); |
328
|
|
|
}, |
329
|
|
|
|
330
|
|
|
/** |
331
|
|
|
* @private |
332
|
|
|
*/ |
333
|
|
|
_setConfirmed: function() { |
334
|
|
|
this.$form.data('apply-query-confirmed', true); |
335
|
|
|
}, |
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* @return {Boolean} |
339
|
|
|
* @private |
340
|
|
|
*/ |
341
|
|
|
_isConfirmed: function() { |
342
|
|
|
return this.$form.data('apply-query-confirmed'); |
343
|
|
|
}, |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* @private |
347
|
|
|
*/ |
348
|
|
|
_showConfirmModal: function() { |
349
|
|
|
if (!this.confirmModalInitialized) { |
350
|
|
|
if (!this.$form.data('productCollectionApplyQueryModal')) { |
351
|
|
|
this.$form.data( |
352
|
|
|
'productCollectionApplyQueryModal', |
353
|
|
|
new StandardConfirmation({ |
354
|
|
|
content: __('oro.product.product_collection.filter_query.confirmation_modal_content'), |
355
|
|
|
okText: __('oro.product.product_collection.filter_query.continue') |
356
|
|
|
}) |
357
|
|
|
); |
358
|
|
|
} |
359
|
|
|
this.$form.data('productCollectionApplyQueryModal').on('ok', _.bind(this.onConfirmModalOk, this)); |
360
|
|
|
this.confirmModalInitialized = true; |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
this.$form.data('productCollectionApplyQueryModal').open(); |
364
|
|
|
}, |
365
|
|
|
|
366
|
|
|
/** |
367
|
|
|
* @private |
368
|
|
|
*/ |
369
|
|
|
_initializeInclusionExclusionSubComponent: function() { |
370
|
|
|
var options = { |
371
|
|
|
_sourceElement: this.options._sourceElement, |
372
|
|
|
scope: this.options.scope, |
373
|
|
|
selectors: { |
374
|
|
|
included: this.options.selectors.included, |
375
|
|
|
excluded: this.options.selectors.excluded |
376
|
|
|
} |
377
|
|
|
}; |
378
|
|
|
this.inclusionExclusionSubComponent = new InclusionExclusionSubComponent(options); |
379
|
|
|
}, |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* @private |
383
|
|
|
*/ |
384
|
|
|
_initializeSelectedProductGridsSubComponent: function() { |
385
|
|
|
var options = { |
386
|
|
|
_sourceElement: this.options._sourceElement, |
387
|
|
|
applyQueryEventName: this.applyQueryEventName, |
388
|
|
|
excludedControlsBlockAlias: this.options.excludedControlsBlockAlias, |
389
|
|
|
includedControlsBlockAlias: this.options.includedControlsBlockAlias, |
390
|
|
|
excludedProductsGridName: this.options.excludedProductsGridName, |
391
|
|
|
includedProductsGridName: this.options.includedProductsGridName, |
392
|
|
|
selectors: { |
393
|
|
|
included: this.options.selectors.included, |
394
|
|
|
excluded: this.options.selectors.excluded |
395
|
|
|
} |
396
|
|
|
}; |
397
|
|
|
this.selectedProductGridSubComponent = new SelectedProductGridSubComponent(options); |
398
|
|
|
}, |
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* @return {Boolean} |
402
|
|
|
* @private |
403
|
|
|
*/ |
404
|
|
|
_isConditionBuilderValid: function() { |
405
|
|
|
var $form = this.$form; |
406
|
|
|
if (!$form.data('validator')) { |
407
|
|
|
return true; |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
$form.valid(); |
411
|
|
|
|
412
|
|
|
var invalidElements = $form.validate().invalidElements(); |
413
|
|
|
if (!invalidElements.length) { |
414
|
|
|
return true; |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
var $conditionBuilder = this.options._sourceElement.find('.condition-builder'); |
418
|
|
|
var conditionBuilderInvalidElements = _.filter(invalidElements, _.bind(function(value) { |
419
|
|
|
return $.contains($conditionBuilder[0], value); |
420
|
|
|
}, this)); |
421
|
|
|
|
422
|
|
|
return !conditionBuilderInvalidElements.length; |
423
|
|
|
}, |
424
|
|
|
|
425
|
|
|
/** |
426
|
|
|
* If conditionBuilderView located in oro-tabs, change form's setting in order to validate hidden fields too. |
427
|
|
|
* Because of it can be hidden. |
428
|
|
|
* |
429
|
|
|
* @private |
430
|
|
|
*/ |
431
|
|
|
_enableHiddenFieldValidation: function() { |
432
|
|
|
var $form = this.$form; |
433
|
|
|
if ($form.data('validator')) { |
434
|
|
|
$form.validate() |
435
|
|
|
.settings |
436
|
|
|
.ignore = ':hidden:not([type=hidden]):not(:parent.' + this.options.controlsBlockAlias + ')'; |
437
|
|
|
} |
438
|
|
|
}, |
439
|
|
|
|
440
|
|
|
dispose: function() { |
441
|
|
|
if (this.disposed) { |
442
|
|
|
return; |
443
|
|
|
} |
444
|
|
|
|
445
|
|
|
if (this.$form.data('productCollectionApplyQueryModal')) { |
446
|
|
|
this.$form.data('productCollectionApplyQueryModal').off('ok', _.bind(this.onConfirmModalOk, this)); |
447
|
|
|
} |
448
|
|
|
this.$form.off(this.eventNamespace()); |
449
|
|
|
mediator.off('grid-sidebar:load:' + this.options.controlsBlockAlias); |
450
|
|
|
mediator.off(this.applyQueryEventName); |
451
|
|
|
|
452
|
|
|
ProductCollectionApplyQueryComponent.__super__.dispose.call(this); |
453
|
|
|
} |
454
|
|
|
}); |
455
|
|
|
|
456
|
|
|
return ProductCollectionApplyQueryComponent; |
457
|
|
|
}); |
458
|
|
|
|