<commit_before>
/**
 * menu bar sql module
 * this module is used to perform custom SQL queries on the table (and the map)
 */

cdb.admin.mod = cdb.admin.mod || {};

cdb.admin.mod.SQL = cdb.core.View.extend({

    buttonClass: 'sql_mod',
    type: 'tool',
    className: "sql_panel",

    events: {
      'click .actions button': 'applyQuery',
      'click .actions a.next': '_do',
      'click .actions a.back': '_undo'
    },

    initialize: function() {
      var self = this;
      this.template = this.getTemplate('table/menu_modules/views/sql');
      this.sqlView = this.options.sqlView;
      this.model.bind('change:query', this._updateSQL, this);
      this.model.bind('change:query_generated', this._updateQueryInfo, this);
      this.sqlView.bind('error', function(e, resp) {
        try {
          var errors = JSON.parse(resp.responseText);
          self._parseError(errors.errors);
        } catch(exp) {
          self._parseError([_t('unknown error')]);
        }
      });

      // Set query position from history array and last sql applied
      var history = this.model.get('query_history')
        , position = this.model.query_history_position
        , sql =  this.model.get('query');

      this.model.query_history_position = _.indexOf(history, sql) || 0;
    },

    activated: function() {
      if(this.codeEditor) {
        this.codeEditor.refresh();
        this.codeEditor.focus();
      }
    },

    _updateSQL: function() {
      if (this.codeEditor) {
        this._clearErrors();
        this.codeEditor.setValue(this.model.get('query') || '');
        this.codeEditor.refresh();
        // Check buttons
        if (this.model.get('query_history'))
          this._checkDoButtons();
      }

      if (this.model.get("query")) {
        $.faviconNotify('/favicons/cartofante_orange.png');
      }
    },

    render: function() {
      this.$el.append(this.template({}));

      /*CodeMirror.commands.autocomplete = function(cm) {
        CodeMirror.simpleHint(cm, CodeMirror.postgresHint);
      };*/

      this.codeEditor = CodeMirror.fromTextArea(this.$('textarea')[0], {
        mode: "text/x-postgres",
        tabMode: "indent",
        matchBrackets: true,
        lineNumbers: true,
        lineWrapping: true//
        //extraKeys: {"Ctrl-Space": "autocomplete"}
      });


      this.$('textarea').bind('keyup', this._checkSubmit.bind(this))


      this._updateSQL();
      this._updateQueryInfo();

      // Add tooltip for undo/redo buttons
      this.$el.find("a.next,a.back").tipsy({
        gravity: "s",
        fade: true
      });

      // Custom scroll code
      // this.$(".panel_content.nano").nanoScroller({
      //   alwaysVisible: true,
      //   flash: true
      // }).bind("scrollend scroll scrolltop enabled disabled", function(e){
      //   var $nano = $(e.currentTarget);

      //   $nano.addClass(e.type);

      //   if (e.type == "enabled") {
      //     $nano.removeClass("disabled");
      //   } else if (e.type == "disabled") {
      //     $nano.removeClass("enabled");
      //   }

      //   if (e.type == "scrolltop") {
      //     $nano.removeClass("scrollend");
      //   } else if (e.type == "scrollend") {
      //     $nano.removeClass("scrolltop");
      //   }
      // });

      return this;
    },

    _checkSubmit: function(ev) {
        if(ev.shiftKey && ev.keyCode === 13) {
          this.applyQuery();
        }
    },

    _parseError: function(errors) {
      // Add error text
      this.$('.info')
        .addClass('error')
        .html(errors.join('<br/>'))
        .show();

      // Fit editor with the error
      var h = this.$('.info').outerHeight();
      this.$('.CodeMirror').css({bottom: '+=' + h + 'px'});
    },

    _updateQueryInfo: function() {
      if(this.model.get('query_generated')) {
        this.$('.info')
          .removeClass('error')
          .html(_t('this query is generated by CartoCSS wizard, if you change it the map may not work'))
          .show();
      } else {
        this.$('.info').hide();
      }
    },

    _clearErrors: function() {
      // Remove error text and hide it
      this.$('.info')
        .removeClass('error')
        .html('')
        .hide();

      // Fit editor with text

    },

    _do: function(e) {
      e.preventDefault();
      this.model.redoQuery();
      return false;
    },

    _undo: function(e) {
      e.preventDefault();
      this.model.undoQuery();
      return false;
    },

    applyQuery: function() {
      var self = this;
      this._clearErrors();
      var sql = this.codeEditor.getValue();
      // if the sql change the table data do not save in the data layer
      // pass though and lauch the query directly to the table
      if(!this.options.table.alterTableData(sql)) {
        this.model.save({ query: sql, query_generated: false });
      } else {
        this.model.save({ query: null, query_generated: false });
        this.trigger('writeSQL', sql);
      }
    },

    _checkDoButtons: function() {
      var history = this.model.get('query_history')
        , position = this.model.query_history_position;

      // Redo
      if ((history[position + 1]) != null) {
        this.$el.find('a.next').removeClass("disabled")
      } else {
        this.$el.find('a.next').addClass("disabled")
      }

      // Undo
      if ((history[position - 1]) != null) {
        this.$el.find('a.back').removeClass("disabled")
      } else {
        this.$el.find('a.back').addClass("disabled")
      }
    }

});
<commit_msg>prevented behaviour on shift+enter<commit_after>
/**
 * menu bar sql module
 * this module is used to perform custom SQL queries on the table (and the map)
 */

cdb.admin.mod = cdb.admin.mod || {};

cdb.admin.mod.SQL = cdb.core.View.extend({

    buttonClass: 'sql_mod',
    type: 'tool',
    className: "sql_panel",

    events: {
      'click .actions button': 'applyQuery',
      'click .actions a.next': '_do',
      'click .actions a.back': '_undo'
    },

    initialize: function() {
      var self = this;
      this.template = this.getTemplate('table/menu_modules/views/sql');
      this.sqlView = this.options.sqlView;
      this.model.bind('change:query', this._updateSQL, this);
      this.model.bind('change:query_generated', this._updateQueryInfo, this);
      this.sqlView.bind('error', function(e, resp) {
        try {
          var errors = JSON.parse(resp.responseText);
          self._parseError(errors.errors);
        } catch(exp) {
          self._parseError([_t('unknown error')]);
        }
      });

      // Set query position from history array and last sql applied
      var history = this.model.get('query_history')
        , position = this.model.query_history_position
        , sql =  this.model.get('query');

      this.model.query_history_position = _.indexOf(history, sql) || 0;
    },

    activated: function() {
      if(this.codeEditor) {
        this.codeEditor.refresh();
        this.codeEditor.focus();
      }
    },

    _updateSQL: function() {
      if (this.codeEditor) {
        this._clearErrors();
        this.codeEditor.setValue(this.model.get('query') || '');
        this.codeEditor.refresh();
        // Check buttons
        if (this.model.get('query_history'))
          this._checkDoButtons();
      }

      if (this.model.get("query")) {
        $.faviconNotify('/favicons/cartofante_orange.png');
      }
    },

    render: function() {
      this.$el.append(this.template({}));

      /*CodeMirror.commands.autocomplete = function(cm) {
        CodeMirror.simpleHint(cm, CodeMirror.postgresHint);
      };*/

      this.codeEditor = CodeMirror.fromTextArea(this.$('textarea')[0], {
        mode: "text/x-postgres",
        tabMode: "indent",
        matchBrackets: true,
        lineNumbers: true,
        lineWrapping: true//
        //extraKeys: {"Ctrl-Space": "autocomplete"}
      });


      this.$('textarea').bind('keypress', this._checkSubmit.bind(this))


      this._updateSQL();
      this._updateQueryInfo();

      // Add tooltip for undo/redo buttons
      this.$el.find("a.next,a.back").tipsy({
        gravity: "s",
        fade: true
      });

      // Custom scroll code
      // this.$(".panel_content.nano").nanoScroller({
      //   alwaysVisible: true,
      //   flash: true
      // }).bind("scrollend scroll scrolltop enabled disabled", function(e){
      //   var $nano = $(e.currentTarget);

      //   $nano.addClass(e.type);

      //   if (e.type == "enabled") {
      //     $nano.removeClass("disabled");
      //   } else if (e.type == "disabled") {
      //     $nano.removeClass("enabled");
      //   }

      //   if (e.type == "scrolltop") {
      //     $nano.removeClass("scrollend");
      //   } else if (e.type == "scrollend") {
      //     $nano.removeClass("scrolltop");
      //   }
      // });

      return this;
    },

    _checkSubmit: function(ev) {
        if(ev.shiftKey && ev.keyCode === 13) {
          this.killEvent(ev);
          this.applyQuery();
        }
    },

    _parseError: function(errors) {
      // Add error text
      this.$('.info')
        .addClass('error')
        .html(errors.join('<br/>'))
        .show();

      // Fit editor with the error
      var h = this.$('.info').outerHeight();
      this.$('.CodeMirror').css({bottom: '+=' + h + 'px'});
    },

    _updateQueryInfo: function() {
      if(this.model.get('query_generated')) {
        this.$('.info')
          .removeClass('error')
          .html(_t('this query is generated by CartoCSS wizard, if you change it the map may not work'))
          .show();
      } else {
        this.$('.info').hide();
      }
    },

    _clearErrors: function() {
      // Remove error text and hide it
      this.$('.info')
        .removeClass('error')
        .html('')
        .hide();

      // Fit editor with text

    },

    _do: function(e) {
      e.preventDefault();
      this.model.redoQuery();
      return false;
    },

    _undo: function(e) {
      e.preventDefault();
      this.model.undoQuery();
      return false;
    },

    applyQuery: function() {
      var self = this;
      this._clearErrors();
      var sql = this.codeEditor.getValue();
      // if the sql change the table data do not save in the data layer
      // pass though and lauch the query directly to the table
      if(!this.options.table.alterTableData(sql)) {
        this.model.save({ query: sql, query_generated: false });
      } else {
        this.model.save({ query: null, query_generated: false });
        this.trigger('writeSQL', sql);
      }
    },

    _checkDoButtons: function() {
      var history = this.model.get('query_history')
        , position = this.model.query_history_position;

      // Redo
      if ((history[position + 1]) != null) {
        this.$el.find('a.next').removeClass("disabled")
      } else {
        this.$el.find('a.next').addClass("disabled")
      }

      // Undo
      if ((history[position - 1]) != null) {
        this.$el.find('a.back').removeClass("disabled")
      } else {
        this.$el.find('a.back').addClass("disabled")
      }
    }

});

{'fraction_non_alphanumeric': 0.165199425080848, 'fraction_numerical': 0.0010779734099892202, 'mean_word_length': 2.0601979109400768, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5560044', 'n_tokens_mistral': 3434, 'n_tokens_neox': 3347, 'n_words': 668}