Test Setup Failed
Push — master ( f42870...11cd9d )
by
unknown
04:18
created

  A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
c 2
b 0
f 0
nc 4
dl 0
loc 14
rs 9.2
nop 2
1
define(function(require) {
2
    'use strict';
3
4
    var HighlightTextView;
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 FuzzySearch = require('oroui/js/fuzzy-search');
10
11
    HighlightTextView = BaseView.extend({
12
        /**
13
         * @inheritDoc
14
         */
15
        optionNames: BaseView.prototype.optionNames.concat([
16
            'text',
17
            'fuzzySearch',
18
            'viewGroup',
19
            'highlightClass', 'elementHighlightClass', 'notFoundClass', 'foundClass',
20
            'highlightSelectors', 'toggleSelectors'
21
        ]),
22
23
        /**
24
         * @property {String}
25
         */
26
        text: '',
27
28
        /**
29
         * @property {RegExp|null}
30
         */
31
        findText: null,
32
33
        /**
34
         * @property {String}
35
         */
36
        fuzzySearch: false,
37
38
        /**
39
         * @property {String}
40
         */
41
        highlightClass: 'highlight-text',
42
43
        /**
44
         * @property {String}
45
         */
46
        elementHighlightClass: 'highlight-element',
47
48
        /**
49
         * @property {String}
50
         */
51
        notFoundClass: 'highlight-not-found',
52
53
        /**
54
         * @property {String}
55
         */
56
        foundClass: 'highlight-found',
57
58
        /**
59
         * @property {String}
60
         */
61
        replaceBy: '',
62
63
        /**
64
         * @property {Array}
65
         */
66
        highlightSelectors: [],
67
68
        /**
69
         * @property {Array}
70
         */
71
        toggleSelectors: {},
72
73
        /**
74
         * @property {String}
75
         */
76
        viewGroup: '',
77
78
        /**
79
         * @inheritDoc
80
         */
81
        initialize: function(options) {
0 ignored issues
show
Unused Code introduced by
The parameter options 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...
82
            this.findHighlightClass = '.' + this.highlightClass;
83
            this.findElementHighlightClass = '.' + this.elementHighlightClass;
84
            this.findNotFoundClass = '.' + this.notFoundClass;
85
            this.findFoundClass = '.' + this.foundClass;
86
            this.replaceBy = '<span class="' + this.highlightClass + '">$&</span>';
87
88
            HighlightTextView.__super__.initialize.apply(this, arguments);
89
90
            this.update(this.text);
91
92
            mediator.on(this.viewGroup + ':highlight-text:update', this.update, this);
93
        },
94
95
        /**
96
         * @inheritDoc
97
         */
98
        render: function() {
99
            this.clear();
100
            this.highlightElements();
101
            this.toggleElements();
102
        },
103
104
        /**
105
         * Refresh highlight using new text
106
         *
107
         * @param {String} text
108
         * @param {Boolean|null} fuzzySearch
109
         */
110
        update: function(text, fuzzySearch) {
111
            if (fuzzySearch !== undefined) {
112
                this.fuzzySearch = fuzzySearch;
113
            }
114
            this.text = text;
115
            var regexp = this.text;
116
            if (this.fuzzySearch) {
117
                regexp = this.text.toLowerCase().replace(/\s/g, '').split('');
118
                regexp = '[' + _.uniq(regexp).join('') + ']';
119
            }
120
            this.findText = this.text.length ? new RegExp(regexp, 'gi') : null;
121
122
            this.render();
123
        },
124
125
        /**
126
         * Highlight text in all found elements
127
         */
128
        highlightElements: function() {
129
            _.each(this.findElements(this.highlightSelectors), this.highlightElement, this);
130
        },
131
132
        /**
133
         * Toggle found/not-found class for all elements based on found highlighted elements
134
         */
135
        toggleElements: function() {
136
            _.each(this.findElements(_.keys(this.toggleSelectors)), this.toggleElement, this);
137
            if (this.isElementHighlighted(this.$el)) {
138
                _.each(this.findElements(_.keys(this.toggleSelectors)), this.toggleElement, this);
139
            }
140
        },
141
142
        /**
143
         * Return found elements with matched selector
144
         *
145
         * @param {Array} selectors
146
         * @return {Array}
147
         */
148
        findElements: function(selectors) {
149
            var elements = [];
150
            _.each(selectors, function(selector) {
151
                this.$(selector).each(function() {
152
                    elements.push({
153
                        selector: selector,
154
                        $el: $(this)
155
                    });
156
                });
157
            }, this);
158
159
            return elements;
160
        },
161
162
        /**
163
         * Toggle found/not-found class for given element based on found highlighted elements
164
         *
165
         * @param {Object} element
166
         */
167
        toggleElement: function(element) {
168
            var $el = element.$el;
169
            if (!$el.is(':visible')) {
170
                return;
171
            }
172
173
            if (this.isElementHighlighted($el)) {
174
                $el.addClass(this.foundClass);
175
                return;
176
            }
177
178
            var $parent = $el.closest(this.toggleSelectors[element.selector]);
179
            if (this.isElementHighlighted($parent)) {
180
                $el.addClass(this.notFoundClass);
181
            }
182
        },
183
184
        /**
185
         * Highlight text in given element
186
         *
187
         * @param {Object} element
188
         */
189
        highlightElement: function(element) {
190
            var $el = element.$el;
191
192
            var $content = this.getElementContent($el);
193
            if (this.findText) {
194
                this.highlightElementContent($content);
195
            }
196
            this.setElementContent($el, $content);
197
        },
198
199
        /**
200
         * Check visible highlighted elements exists in given element
201
         *
202
         * @param {jQuery} $el
203
         * @return {boolean}
204
         */
205
        isElementHighlighted: function($el) {
206
            var $highlighted = $el.find(this.findElementHighlightClass);
207
            if ($el.hasClass(this.elementHighlightClass)) {
208
                $highlighted = $highlighted.add($el);
209
            }
210
            return $highlighted.filter(':visible').length > 0;
211
        },
212
213
        /**
214
         * Check highlighted text exists in given element
215
         *
216
         * @param {jQuery} $el
217
         * @param {Boolean|null} filterVisible
218
         * @return {boolean}
219
         */
220
        isElementContentHighlighted: function($el, filterVisible) {
221
            var $highlighted = $el.find(this.findHighlightClass);
222
            if (filterVisible !== false) {
223
                $highlighted = $highlighted.filter(':visible');
224
            }
225
            return $highlighted.length > 0;
226
        },
227
228
        /**
229
         * Remove highlight from all elements
230
         */
231
        clear: function() {
232
            _.each(this.$el.find(this.findElementHighlightClass), function(element) {
233
                var $el = $(element);
234
                var $content = this.getElementContent($el);
235
236
                $el.removeClass(this.elementHighlightClass);
237
                $content.find(this.findHighlightClass).each(function() {
238
                    var $el = $(this);
239
                    $el.replaceWith($el.html());
240
                });
241
242
                if (!this._isFieldChoice($el)) {
243
                    this.setElementContent($el, $content);
244
                }
245
            }, this);
246
247
            this.$el.find(this.findNotFoundClass).removeClass(this.notFoundClass);
248
            this.$el.find(this.findFoundClass).removeClass(this.foundClass);
249
        },
250
251
        /**
252
         * Return element content, based on element type
253
         *
254
         * @param {jQuery} $el
255
         * @return {jQuery}
256
         */
257
        getElementContent: function($el) {
258
            var content;
259
260
            var isPopover = $el.data('popover');
261
            if (isPopover) {
262
                content = $el.data('popover').getContent();
263
            } else if (this._isField($el) && !this._isFieldChoice($el)) {
264
                content = $el.val();
265
            } else {
266
                content = $el.html();
267
            }
268
269
            return $('<div/>').html(content);
270
        },
271
272
        /**
273
         * Set processed content to element
274
         *
275
         * @param {jQuery} $el
276
         * @param {jQuery} $content
277
         */
278
        setElementContent: function($el, $content) {
279
            var isPopover = $el.data('popover');
280
            if (isPopover) {
281
                $el.data('popover').updateContent($content.html());
282
                $el.toggleClass(this.elementHighlightClass, this.isElementContentHighlighted($content, false));
283
            } else if (this._isFieldChoice($el)) {
284
                $el.parent().toggleClass(this.elementHighlightClass, this.isElementContentHighlighted($content, false));
285
            } else if (this._isField($el)) {
286
                $el.toggleClass(this.elementHighlightClass, this.isElementContentHighlighted($content, false));
287
            } else {
288
                $el.html($content.html());
289
                $el.toggleClass(this.elementHighlightClass, this.isElementContentHighlighted($el));
290
            }
291
        },
292
293
        /**
294
         * Highlight text in given content
295
         *
296
         * @param {jQuery} $content
297
         */
298
        highlightElementContent: function($content) {
299
            _.each($content.contents(), function(children) {
300
                var $children = $(children);
301
                if (children.nodeName === '#text') {
302
                    var text = $children.text();
303
                    if (!this.fuzzySearch || FuzzySearch.isMatched(_.trim(text), this.text)) {
304
                        text = text.replace(this.findText, this.replaceBy);
305
                        $children.replaceWith(text);
306
                    }
307
                } else {
308
                    this.highlightElementContent($children);
309
                }
310
            }, this);
311
        },
312
313
        /**
314
         * Check if given element is field
315
         *
316
         * @param {jQuery} $element
317
         */
318
        _isFieldChoice: function($element) {
319
            var $child;
320
            var isFieldChoice = this._isField($element) && $element.is('select');
321
            if (!isFieldChoice) {
322
                $child = $element.children('select');
323
                if ($child.length) {
324
                    return true;
325
                }
326
            }
327
328
            return isFieldChoice;
329
        },
330
331
        /**
332
         * Check if given element is field
333
         *
334
         * @param {jQuery} $element
335
         */
336
        _isField: function($element) {
337
            var elementName = $element.data('name');
338
            var fieldName = 'field__value';
339
340
            return elementName === fieldName;
341
        }
342
    });
343
344
    return HighlightTextView;
345
});
346