<commit_before>angular.module('yds').directive('queryBuilder', ['$compile', '$ocLazyLoad', 'Data', 'Search', 'queryBuilderService',
    function ($compile, $ocLazyLoad, Data, Search, queryBuilderService) {
        return {
            restrict: 'E',
            scope: {
                lang:'@',
                maxSuggestions: '@',
                concept: '@'
            },
            templateUrl: 'templates/query-builder.html',
            link: function (scope) {
                scope.qbInputs = {};		// Keeps the QueryBuilder's typeahead ng models
                scope.randomId = Data.createRandomId();
                scope.builderId = "builder" + scope.randomId;
                scope.noFilters = false;

                // Lazy load jQuery QueryBuilder and add it to the page
                $ocLazyLoad.load({
                    files: [
                        "https://code.jquery.com/jquery-2.2.4.min.js",
                        "css/query-builder.default.min.css",
                        "lib/query-builder.standalone.min.js"
                    ],
                    cache: true,
                    serie: true
                }).then(function () {
                    var builder = $("#" + scope.builderId);

                    // Get filters for query builder
                    Search.getQueryBuilderFilters(scope.concept)
                        .then(function(filters) {
                            // Format filters in the format QueryBuilder expects
                            var formattedFilters = formatFilters(filters);

                            // If there are filters, create builder
                            if (!_.isEmpty(formattedFilters)) {
                                // Create empty builder (no rules)
                                builder.queryBuilder({
                                    filters: formattedFilters
                                });

                                // Watch for all changes in the builder, and update the rules in QueryBuilderService
                                // (https://github.com/mistic100/jQuery-QueryBuilder/issues/195)
                                builder.on("afterDeleteGroup.queryBuilder afterUpdateRuleFilter.queryBuilder " +
                                    "afterAddRule.queryBuilder afterDeleteRule.queryBuilder afterUpdateRuleValue.queryBuilder " +
                                    "afterUpdateRuleOperator.queryBuilder afterUpdateGroupCondition.queryBuilder ", function (e) {
                                    queryBuilderService.setRules(builder.queryBuilder('getRules'));
                                }).on('validationError.queryBuilder', function (e, rule, error, value) {
                                    // Don't display QueryBuilder's validation errors
                                    e.preventDefault();
                                });
                            } else {
                                // Show information box saying there are no filters
                                scope.noFilters = true;
                            }
                        });
                });

                /**
                 * Changes the filters array as returned from the server, to add typeahead in string fields
                 * and get the correct labels depending on the language of the component
                 * @param filters       Filters as returned from the server
                 * @returns {Array}     Formatted filters
                 */
                var formatFilters = function(filters) {
                    var availLangs = Search.geti18nLangs();

                    var newFilters = filters.map(function(obj) {
                        // Find the label the filter should have depending on language
                        var label = obj["label"][scope.lang];
                        if (_.isUndefined(label)) {
                            var otherLang = _.first(_.without(availLangs, scope.lang));
                            label = obj["label"][otherLang];
                        }

                        // If filter is string, add typeahead to it
                        //todo

                        // Return the filter
                        return {
                            id: obj["id"].replace(/\W/g, ''),
                            label: label,
                            type: obj["type"]                           //todo: add date time plugin
                        };
                    });

                    return newFilters;
                };

                /**
                 * Recursive function that checks if a group has the specified rule, and sets its value
                 * If a rule is a group, it calls itself with that group as parameter
                 * @param group		Group to search inside
                 * @param ruleId	id of the rule to find
                 * @param value		Value to give to the rule
                 */
                var setRule = function(group, ruleId, value) {
                    // For each rule, check if it has the desired id or if it's a group, check inside of it
                    _.each(group.rules, function(rule) {<commit_msg>String fields in QueryBuilder have suggestions (again)<commit_after>angular.module('yds').directive('queryBuilder', ['$compile', '$ocLazyLoad', 'Data', 'Search', 'queryBuilderService',
    function ($compile, $ocLazyLoad, Data, Search, queryBuilderService) {
        return {
            restrict: 'E',
            scope: {
                lang:'@',
                maxSuggestions: '@',
                concept: '@'
            },
            templateUrl: 'templates/query-builder.html',
            link: function (scope) {
                scope.qbInputs = {};		// Keeps the QueryBuilder's typeahead ng models
                scope.randomId = Data.createRandomId();
                scope.builderId = "builder" + scope.randomId;
                scope.noFilters = false;

                // Lazy load jQuery QueryBuilder and add it to the page
                $ocLazyLoad.load({
                    files: [
                        "https://code.jquery.com/jquery-2.2.4.min.js",
                        "css/query-builder.default.min.css",
                        "lib/query-builder.standalone.min.js"
                    ],
                    cache: true,
                    serie: true
                }).then(function () {
                    var builder = $("#" + scope.builderId);

                    // Get filters for query builder
                    Search.getQueryBuilderFilters(scope.concept)
                        .then(function(filters) {
                            // Format filters in the format QueryBuilder expects
                            var formattedFilters = formatFilters(filters);

                            // If there are filters, create builder
                            if (!_.isEmpty(formattedFilters)) {
                                // Create empty builder (no rules)
                                builder.queryBuilder({
                                    filters: formattedFilters
                                });

                                // Watch for all changes in the builder, and update the rules in QueryBuilderService
                                // (https://github.com/mistic100/jQuery-QueryBuilder/issues/195)
                                builder.on("afterDeleteGroup.queryBuilder afterUpdateRuleFilter.queryBuilder " +
                                    "afterAddRule.queryBuilder afterDeleteRule.queryBuilder afterUpdateRuleValue.queryBuilder " +
                                    "afterUpdateRuleOperator.queryBuilder afterUpdateGroupCondition.queryBuilder ", function (e) {
                                    queryBuilderService.setRules(builder.queryBuilder('getRules'));
                                }).on('validationError.queryBuilder', function (e, rule, error, value) {
                                    // Don't display QueryBuilder's validation errors
                                    e.preventDefault();
                                });
                            } else {
                                // Show information box saying there are no filters
                                scope.noFilters = true;
                            }
                        });
                });

                /**
                 * Changes the filters array as returned from the server, to add typeahead in string fields
                 * and get the correct labels depending on the language of the component
                 * @param filters       Filters as returned from the server
                 * @returns {Array}     Formatted filters
                 */
                var formatFilters = function(filters) {
                    var availLangs = Search.geti18nLangs();

                    var newFilters = filters.map(function(obj) {
                        // Find the label the filter should have depending on language
                        var label = obj["label"][scope.lang];
                        if (_.isUndefined(label)) {
                            var otherLang = _.first(_.without(availLangs, scope.lang));
                            label = obj["label"][otherLang];
                        }

                        // Create filter object
                        var filter = {
                            id: obj.id.replace(/\W/g, ''),          // keep only alphanumeric id characters
                            label: label,
                            type: obj.type                          // todo: add date time plugin
                        };

                        // If filter is string, add typeahead to it
                        if (obj.type == "string") {
                            filter.input = function(rule, name) {
                                // Return html of text input element with typeahead
                                return $compile('<input type="text" class="form-control" name="typeahead"\
                                    placeholder="Type here..." ng-model="qbInputs.' + rule.id + '" \
                                    typeahead-popup-template-url="templates/search-typeahead-popup-small.html"\
                                    uib-typeahead="suggestion for suggestion in getSuggestions($viewValue)" \
                                    typeahead-focus-first="false" autocomplete="off" \
                                    typeahead-on-select="typeaheadSelectHandler(\'' + rule.id + '\', $item)" \
                                    typeahead-append-to-body="true">')( scope );
                            };

                            filter.valueGetter = function(rule) {
                                return scope.qbInputs[rule.id];
                            };

                            filter.valueSetter = function(rule, value) {
                                scope.qbInputs[rule.id] = value;
                            };
                        }


                        // Return the filter
                        return filter;
                    });

                    return newFilters;
                };

                /**
                 * Recursive function that checks if a group has the specified rule, and sets its value
                 * If a rule is a group, it calls itself with that group as parameter
                 * @param group		Group to search inside
                 * @param ruleId	id of the rule to find
                 * @param value		Value to give to the rule
                 */
                var setRule = function(group, ruleId, value) {
                    // For each rule, check if it has the desired id or if it's a group, check inside of it
                    _.each(group.rules, function(rule) {
{'fraction_non_alphanumeric': 0.08223684210526316, 'fraction_numerical': 0.001855600539811066, 'mean_word_length': 1.0617283950617284, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 27, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2745727', 'n_tokens_mistral': 2581, 'n_tokens_neox': 2410, 'n_words': 687}