<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>jQuery QueryBuilder Example</title>

  <link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.css" id="bt-theme">
  <link rel="stylesheet" href="../node_modules/bootstrap-select/dist/css/bootstrap-select.css">
  <link rel="stylesheet" href="../node_modules/chosenjs/chosen.css">
  <link rel="stylesheet" href="../node_modules/awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css">
  <link rel="stylesheet" href="../node_modules/bootstrap-slider/dist/css/bootstrap-slider.css">
  <link rel="stylesheet" href="../node_modules/selectize/dist/css/selectize.bootstrap3.css">

  <link rel="stylesheet" href="../dist/css/query-builder.default.css" id="qb-theme">
  <link rel="stylesheet" href="http://mistic100.github.io/jQuery-QueryBuilder/assets/flags/flags.css">

  <style>
    .flag {
      display: inline-block;
    }
  </style>
</head>

<body>

<div class="container">
  <div class="col-md-12 col-lg-10 col-lg-offset-1">
    <div class="page-header">
      <a class="pull-right" href="https://github.com/mistic100/jQuery-QueryBuilder">
        <img src="https://assets.github.com/images/icons/emoji/octocat.png" width=48px height=48px>
      </a>
      <h1>jQuery QueryBuilder
        <small>Example</small>
      </h1>
    </div>

    <div class="well well-sm">
      <label>Theme:</label>
      <div class="btn-group">
        <button class="btn btn-primary btn-sm change-theme" data-qb="../dist/css/query-builder.default.css"
                data-bt="../node_modules/bootstrap/dist/css/bootstrap.css">Default
        </button>
        <button class="btn btn-primary btn-sm change-theme" data-qb="../dist/css/query-builder.dark.css"
                data-bt="../node_modules/bootswatch-dist/css/bootstrap.css">Dark
        </button>
      </div>

      <label>Language:</label>
      <select name="language" class="selectpicker show-tick show-menu-arrow" data-width="auto">
        <option value="sq" data-icon="flag flag-al">Albanian</option>
        <option value="ar" data-icon="flag flag-ar">Arabic</option>
        <option value="az" data-icon="flag flag-az">Azerbaijani</option>
        <option value="bg" data-icon="flag flag-bg">Bulgarian</option>
        <option value="zh-CN" data-icon="flag flag-zh-CN">Simplified Chinese</option>
        <option value="cs" data-icon="flag flag-cs">Czech</option>
        <option value="de" data-icon="flag flag-de">German</option>
        <option value="da" data-icon="flag flag-dk">Danish</option>
        <option value="nl" data-icon="flag flag-nl">Dutch</option>
        <option value="en" data-icon="flag flag-gb" selected>English</option>
        <option value="fa-IR" data-icon="flag flag-ir">Farsi</option>
        <option value="fr" data-icon="flag flag-fr">French</option>
        <option value="el" data-icon="flag flag-el">Greek</option>
        <option value="he" data-icon="flag flag-he">Hebrew</option>
        <option value="it" data-icon="flag flag-it">Italian</option>
        <option value="no" data-icon="flag flag-no">Norwegian</option>
        <option value="pl" data-icon="flag flag-pl">Polish</option>
        <option value="pt-PT" data-icon="flag flag-pt-PT">Portuguese</option>
        <option value="pt-BR" data-icon="flag flag-pt-BR">Brazilian Portuguese</option>
        <option value="ro" data-icon="flag flag-ro">Romanian</option>
        <option value="ru" data-icon="flag flag-ru">Russian</option>
        <option value="es" data-icon="flag flag-es">Spanish</option>
        <option value="tr" data-icon="flag flag-tr">Turkish</option>
        <option value="ua" data-icon="flag flag-ua">Ukrainian</option>
      </select>
    </div>

    <div id="builder"></div>

    <div class="btn-group">
      <button class="btn btn-danger reset">Reset</button>
      <button class="btn btn-warning set-filters" data-toggle="tooltip" data-container="body" data-placement="bottom"
              title="Adds a filter 'New filter' and removes 'Coordinates', 'State', 'BSON'">Set filters
      </button>
    </div>

    <div class="btn-group">
      <button class="btn btn-default" disabled>Set:</button>
      <button class="btn btn-success set">From JSON</button>
      <button class="btn btn-success set-mongo">From MongoDB</button>
      <button class="btn btn-success set-sql">From SQL</button>
    </div>

    <div class="btn-group">
      <button class="btn btn-default" disabled>Get:</button>
      <button class="btn btn-primary parse-json">JSON</button>
      <button class="btn btn-primary parse-sql" data-stmt="false">SQL</button>
      <button class="btn btn-primary parse-sql" data-stmt="question_mark">SQL statement</button>
      <button class="btn btn-primary parse-mongo">MongoDB</button>
    </div>

    <div id="result" class="hide">
      <h3>Output</h3>
      <pre></pre>
    </div>
  </div>
</div>

<script src="../node_modules/jquery/dist/jquery.js"></script>
<script src="../node_modules/bootstrap/dist/js/bootstrap.js"></script>
<script src="../node_modules/bootstrap-select/dist/js/bootstrap-select.js"></script>
<script src="../node_modules/chosenjs/chosen.jquery.js"></script>
<script src="../node_modules/bootbox/bootbox.js"></script>
<script src="../node_modules/bootstrap-slider/dist/bootstrap-slider.js"></script>
<script src="../node_modules/selectize/dist/js/standalone/selectize.js"></script>
<script src="../node_modules/jquery-extendext/jQuery.extendext.js"></script>
<script src="../node_modules/sql-parser-mistic/browser/sql-parser.js"></script>
<script src="../node_modules/dot/doT.js"></script>
<script src="../node_modules/interactjs/dist/interact.js"></script>

<!-- <script src="../dist/js/query-builder.js"></script> -->
<!-- injector:js -->
<script src="../src/main.js"></script>
<script src="../src/defaults.js"></script>
<script src="../src/plugins.js"></script>
<script src="../src/core.js"></script>
<script src="../src/public.js"></script>
<script src="../src/data.js"></script>
<script src="../src/template.js"></script>
<script src="../src/utils.js"></script>
<script src="../src/model.js"></script>
<script src="../src/jquery.js"></script>
<script src="../src/plugins/bt-checkbox/plugin.js"></script>
<script src="../src/plugins/bt-selectpicker/plugin.js"></script>
<script src="../src/plugins/bt-tooltip-errors/plugin.js"></script>
<script src="../src/plugins/change-filters/plugin.js"></script>
<script src="../src/plugins/chosen-selectpicker/plugin.js"></script>
<script src="../src/plugins/filter-description/plugin.js"></script>
<script src="../src/plugins/invert/plugin.js"></script>
<script src="../src/plugins/mongodb-support/plugin.js"></script>
<script src="../src/plugins/not-group/plugin.js"></script>
<script src="../src/plugins/sortable/plugin.js"></script>
<script src="../src/plugins/sql-support/plugin.js"></script>
<script src="../src/plugins/unique-filter/plugin.js"></script>
<script src="../dist/i18n/query-builder.en.js"></script>
<!-- endinjector -->

<script>
  $('[data-toggle="tooltip"]').tooltip();

  var $b = $('#builder');

  var options = {
    allow_empty: true,

    //default_filter: 'name',
    sort_filters: true,

    optgroups: {
      core: {
        en: 'Core',
        fr: 'Coeur'
      }
    },

    plugins: {
      'bt-tooltip-errors': { delay: 100 },
      'sortable': null,
      'filter-description': { mode: 'bootbox' },
      'bt-selectpicker': null,
//      'chosen-selectpicker': null,
      'unique-filter': null,
      'bt-checkbox': { color: 'primary' },
      'invert': null,
      'not-group': null
    },

    // standard operators in custom optgroups
    operators: [
      { type: 'equal', optgroup: 'basic' },
      { type: 'not_equal', optgroup: 'basic' },
      { type: 'in', optgroup: 'basic' },
      { type: 'not_in', optgroup: 'basic' },
      { type: 'less', optgroup: 'numbers' },
      { type: 'less_or_equal', optgroup: 'numbers' },
      { type: 'greater', optgroup: 'numbers' },
      { type: 'greater_or_equal', optgroup: 'numbers' },
      { type: 'between', optgroup: 'numbers' },
      { type: 'not_between', optgroup: 'numbers' },
      { type: 'begins_with', optgroup: 'strings' },
      { type: 'not_begins_with', optgroup: 'strings' },
      { type: 'contains', optgroup: 'strings' },
      { type: 'not_contains', optgroup: 'strings' },
      { type: 'ends_with', optgroup: 'strings' },
      { type: 'not_ends_with', optgroup: 'strings' },
      { type: 'is_empty' },
      { type: 'is_not_empty' },
      { type: 'is_null' },
      { type: 'is_not_null' }
    ],

    filters: [
      /*
       * string with separator
       */
      {
        id: 'name',
        field: 'username',
        label: {
          en: 'Name',
          fr: 'Nom'
        },
        icon: 'glyphicon glyphicon-user',
        value_separator: ',',
        type: 'string',
        optgroup: 'core',
        default_value: 'Mistic',
        size: 30,
        validation: {
          allow_empty_value: true
        },
        unique: true
      },
      /*
       * integer with separator for 'in' and 'not_in'
       */
      {
        id: 'age',
        label: 'Age',
        icon: 'glyphicon glyphicon-calendar',
        type: 'integer',
        input: 'text',
        value_separator: '|',
        optgroup: 'core',
        description: function(rule) {
          if (rule.operator && ['in', 'not_in'].indexOf(rule.operator.type) !== -1) {
            return 'Use a pipe (|) to separate multiple values with "in" and "not in" operators';
          }
        }
      },
      /*
       * textarea
       */
      {
        id: 'bson',
        label: 'BSON',
        icon: 'glyphicon glyphicon-qrcode',
        type: 'string',
        input: 'textarea',
        operators: ['equal'],
        size: 30,
        rows: 3
      },
      /*
       * checkbox
       */
      {
        id: 'category',
        label: 'Category',
        icon: 'glyphicon glyphicon-th-list',
        type: 'integer',
        input: 'checkbox',
        optgroup: 'core',
        values: {
          1: 'Books',
          2: 'Movies',
          3: 'Music',
          4: 'Tools',
          5: 'Goodies',
          6: 'Clothes'
        },
        colors: {
          1: 'foo',
          2: 'warning',
          5: 'success'
        },
        operators: ['equal', 'not_equal', 'in', 'not_in', 'is_null', 'is_not_null'],
        default_operator: 'in'
      },
      /*
       * select
       */
      {
        id: 'continent',
        label: 'Continent',
        icon: 'glyphicon glyphicon-globe',
        type: 'string',
        input: 'select',
        optgroup: 'core',
        placeholder: 'Select something',
        values: [
          {
            label: 'Europe',
            value: 'eur',
            optgroup: 'North'
          },
          {
            label: 'Asia',
            value: 'asia',
            optgroup: 'North'
          },
          {
            label: 'Oceania',
            value: 'oce',
            optgroup: 'South'
          },
          {
            label: 'Africa',
            value: 'afr',
            optgroup: 'South'
          },
          {
            label: 'North America',
            value: 'na',
            optgroup: 'North'
          },
          {
            label: 'South America',
            value: 'sa',
            optgroup: 'South'
          },
          {
            label: 'Mordor',
            value: 'mrd'
          }
        ],
        operators: ['equal', 'not_equal', 'is_null', 'is_not_null']
      },
      /*
       * Selectize
       */
      {
        id: 'state',
        label: 'State',
        icon: 'glyphicon glyphicon-globe',
        type: 'string',
        input: 'select',
        multiple: true,
        plugin: 'selectize',
        plugin_config: {
          valueField: 'id',
          labelField: 'name',
          searchField: 'name',
          sortField: 'name',
          options: [
            { id: "AL", name: "Alabama" },
            { id: "AK", name: "Alaska" },
            { id: "AZ", name: "Arizona" },
            { id: "AR", name: "Arkansas" },
            { id: "CA", name: "California" },
            { id: "CO", name: "Colorado" },
            { id: "CT", name: "Connecticut" },
            { id: "DE", name: "Delaware" },
            { id: "DC", name: "District of Columbia" },
            { id: "FL", name: "Florida" },
            { id: "GA", name: "Georgia" },
            { id: "HI", name: "Hawaii" },
            { id: "ID", name: "Idaho" }
          ]
        },
        valueSetter: function(rule, value) {
          rule.$el.find('.rule-value-container select')[0].selectize.setValue(value);
        }
      },
      /*
       * radio
       */
      {
        id: 'in_stock',
        label: 'In stock',
        icon: 'glyphicon glyphicon-log-in',
        type: 'integer',
        input: 'radio',
        optgroup: 'plugin',
        values: {
          1: 'Yes',
          0: 'No'
        },
        operators: ['equal']
      },
      /*
       * double
       */
      {
        id: 'price',
        label: 'Price',
        icon: 'glyphicon glyphicon-usd',
        type: 'double',
        size: 5,
        validation: {
          min: 0,
          step: 0.01
        },
        data: {
          class: 'com.example.PriceTag'
        }
      },
      /*
       * slider
       */
      {
        id: 'rate',
        label: 'Rate',
        icon: 'glyphicon glyphicon-flash',
        type: 'integer',
        validation: {
          min: 0,
          max: 100
        },
        plugin: 'slider',
        plugin_config: {
          min: 0,
          max: 100,
          value: 0
        },
        onAfterSetValue: function(rule, value) {
          var input = rule.$el.find('.rule-value-container input');
          input.slider('setValue', value);
          input.val(value); // don't know why I need it
        }
      },
      /*
       * placeholder and regex validation
       */
      {
        id: 'id',
        label: 'Identifier',
        icon: 'glyphicon glyphicon-sunglasses',
        type: 'string',
        optgroup: 'plugin',
        placeholder: '____-____-____',
        size: 14,
        operators: ['equal', 'not_equal'],
        validation: {
          format: /^.{4}-.{4}-.{4}$/,
          messages: {
            format: 'Invalid format, expected: AAAA-AAAA-AAAA'
          }
        }
      },
      /*
       * custom input
       */
      {
        id: 'coord',
        label: 'Coordinates',
        icon: 'glyphicon glyphicon-star-empty',
        type: 'string',
        default_value: 'C.5',
        description: 'The letter is the cadran identifier:\
<ul>\
  <li><b>A</b>: alpha</li>\
  <li><b>B</b>: beta</li>\
  <li><b>C</b>: gamma</li>\
</ul>',
        validation: {
          format: /^[A-C]{1}.[1-6]{1}$/
        },
        input: function(rule, name) {
          var $container = rule.$el.find('.rule-value-container');

          $container.on('change', '[name=' + name + '_1]', function() {
            var h = '';

            switch ($(this).val()) {
              case 'A':
                h = '<option value="-1">-</option> <option value="1">1</option> <option value="2">2</option>';
                break;
              case 'B':
                h = '<option value="-1">-</option> <option value="3">3</option> <option value="4">4</option>';
                break;
              case 'C':
                h = '<option value="-1">-</option> <option value="5">5</option> <option value="6">6</option>';
                break;
            }

            $container.find('[name$=_2]')
              .html(h).toggle(!!h)
              .val('-1').trigger('change');
          });

          return '\
<select name="' + name + '_1"> \
  <option value="-1">-</option> \
  <option value="A">A</option> \
  <option value="B">B</option> \
  <option value="C">C</option> \
</select> \
<select name="' + name + '_2" style="display:none;"></select>';
        },
        valueGetter: function(rule) {
          return rule.$el.find('.rule-value-container [name$=_1]').val()
            + '.' + rule.$el.find('.rule-value-container [name$=_2]').val();
        },
        valueSetter: function(rule, value) {
          if (rule.operator.nb_inputs > 0) {
            var val = value.split('.');

            rule.$el.find('.rule-value-container [name$=_1]').val(val[0]).trigger('change');
            rule.$el.find('.rule-value-container [name$=_2]').val(val[1]).trigger('change');
          }
        }
      }]
  };

  // init
  $('#builder').queryBuilder(options);

  $('#builder').on('afterCreateRuleInput.queryBuilder', function(e, rule) {
    if (rule.filter.plugin == 'selectize') {
      rule.$el.find('.rule-value-container').css('min-width', '200px')
        .find('.selectize-control').removeClass('form-control');
    }
  });

  // change language
  $('[name=language]').selectpicker().on('change', function() {
    var lang = $(this).val();

    var done = function() {
      var rules = $b.queryBuilder('getRules');
      if (!$.isEmptyObject(rules)) {
        options.rules = rules;
      }
      else {
        delete options.rules;
      }
      options.lang_code = lang;
      $b.queryBuilder('destroy');
      $('#builder').queryBuilder(options);
    };

    if ($.fn.queryBuilder.regional[lang] === undefined) {
      $.getScript('../dist/i18n/query-builder.' + lang + '.js', done);
    }
    else {
      done();
    }
  });

  // change theme
  $('.change-theme').on('click', function() {
    $('#qb-theme').replaceWith('<link rel="stylesheet" href="' + $(this).data('qb') + '" id="qb-theme">');
    $('#bt-theme').replaceWith('<link rel="stylesheet" href="' + $(this).data('bt') + '" id="bt-theme">');
  });

  // set rules
  $('.set').on('click', function() {
    $('#builder').queryBuilder('setRules', {
      condition: 'AND',
      flags: {
        condition_readonly: true
      },
      rules: [{
        id: 'price',
        operator: 'between',
        value: [10.25, 15.52],
        flags: {
          no_delete: true,
          filter_readonly: true
        },
        data: {
          unit: '€'
        }
      }, {
        id: 'state',
        operator: 'equal',
        value: 'AK'
      }, {
        condition: 'OR',
        not: true,
        flags: {
          no_delete: true,
          no_drop: true,
          no_sortable: true
        },
        rules: [{
          id: 'category',
          operator: 'equal',
          value: 2
        }, {
          id: 'coord',
          operator: 'equal',
          value: undefined // will use filter's default value
        }]
      }, {
        id: 'name',
        operator: 'in',
        value: ['Mistic', 'Damien']
      }, {
        id: 'age',
        operator: 'in',
        value: [20,21,22]
      }, {
        empty: true
      }]
    });
  });

  // set rules from MongoDB
  $('.set-mongo').on('click', function() {
    $('#builder').queryBuilder('setRulesFromMongo', {
      "$or": [{
        "username": {
          "$regex": "^(?!Mistic)"
        }
      }, {
        "price": { "$gte": 0, "$lte": 100 }
      }, {
        "$nor": [{
          "$and": [{
            "category": 2
          }, {
            "category": { "$in": [4, 5] }
          }]
        }]
      }]
    });
  });

  // set rules from SQL
  $('.set-sql').on('click', function() {
    $('#builder').queryBuilder('setRulesFromSQL', 'username NOT LIKE "Mistic%" OR price BETWEEN 100 OR 200 OR NOT (category IN(1, 2) AND rate <= 2)');
  });

  // reset builder
  $('.reset').on('click', function() {
    $('#builder').queryBuilder('reset');
    $('#result').addClass('hide').find('pre').empty();
  });

  // get rules
  $('.parse-json').on('click', function() {
    $('#result').removeClass('hide')
      .find('pre').html(JSON.stringify(
      $('#builder').queryBuilder('getRules', {
        get_flags: true,
        skip_empty: true
      }),
      undefined, 2
    ));
  });

  $('.parse-sql').on('click', function() {
    var res = $('#builder').queryBuilder('getSQL', $(this).data('stmt'), false);
    $('#result').removeClass('hide')
      .find('pre').html(
      res.sql + (res.params ? '\n\n' + JSON.stringify(res.params, undefined, 2) : '')
    );
  });

  $('.parse-mongo').on('click', function() {
    $('#result').removeClass('hide')
      .find('pre').html(JSON.stringify(
      $('#builder').queryBuilder('getMongo'),
      undefined, 2
    ));
  });

  // set filters
  $('.set-filters').on('click', function() {
    $(this).prop('disabled', true);
    $(this).tooltip('hide');

    // add a new filter after 'state'
    $('#builder').queryBuilder('addFilter',
      {
        id: 'new_one',
        label: 'New filter',
        type: 'string'
      },
      'state'
    );

    // remove filter 'coord'
    $('#builder').queryBuilder('removeFilter',
      ['coord', 'state', 'bson'],
      true
    );

    // also available : 'setFilters'
  });
</script>

<script>
  document.write('<script src="//' + location.host.split(':')[0] + ':35729/livereload.js" async defer><' + '/script>');
</script>
</body>
</html>