<commit_before>view = Backbone.View.extend();

view.prototype.events = {
    'click .swatch': 'colorOpen',
    'click .swatch a[href=#save]': 'colorSave',
    'click .swatch a[href=#close]': 'colorClose',
    'click a.add': 'stylesheetAdd',
    'click a.icon': 'stylesheetDelete',
    'sortupdate .tabs': 'sortStylesheets',
    'click .status a[href=#close]': 'statusClose'
};

view.prototype.initialize = function() {
    _(this).bindAll(
        'render',
        'attach',
        'save',
        'error',
        'makeStylesheet',
        'stylesheetAdd',
        'stylesheetDelete',
        'sortStylesheets',
        'statusClose',
        'colors',
        'colorOpen',
        'colorSave',
        'colorClose'
    );
    this.model.bind('save', this.save);
    this.model.bind('saved', this.attach);
    this.model.bind('error', this.error);
    this.model.bind('poll', this.render);
    this.model.bind('poll', this.attach);
    this.render().attach();
};

view.prototype.render = function(init) {
    $(this.el).html(templates.Editor());
    this.model.get('Stylesheet').chain().each(this.makeStylesheet);
    this.$('.tabs').sortable({
        axis: 'x',
        containment: 'parent',
        tolerance: 'pointer'
    });
    return this;
};

view.prototype.attach = function() {
    this.statusClose();
    this.colors();
    return this;
};

view.prototype.save = function() {
    this.model.get('Stylesheet').forEach(function(model) {
        if (model.errors) {
            model.errors = [];
            for (i = 0; i < (model.codemirror.getValue().match(/\n/g)||[]).length+1; i++) {
                model.codemirror.clearMarker(i);
            }
        }
    });
    this.$('.tabs a.error').removeClass('error');
};

// Test for a Carto error of the form
//
//     style.mss:2 Invalid value for background-color ...
//
// and highlight the line number and stylesheet appropriately if
// found. Otherwise, display error in a modal.
view.prototype.error = function(model, resp) {
    if (resp.responseText) {
        // this assume Carto.js specific error array format response
        var err_message = JSON.parse(resp.responseText).message;
        var err_group = _(err_message.toString().split('\n')).compact();
        for (var i = 0; i < err_group.length; i++) {
            var match = err_group[i].match(/^(Error: )?([\w.]+):([\d]+):([\d]+) (.*)$/);
            if (match) {
                var stylesheet = this.model.get('Stylesheet').get(match[2]),
                    id = 'stylesheet-' + stylesheet.id.replace(/[\.]/g, '-'),
                    lineNum = parseInt(match[3]) - 1;
                this.$('.tabs a[href=#' + id + ']').addClass('error');
                stylesheet.errors = stylesheet.errors || [];
                stylesheet.errors[lineNum] = match[5];
                stylesheet.codemirror.setMarker(lineNum, '%N%', 'error');
                var error_message = match[5] + ' (line ' + lineNum + ')';
                if (err_group.length == 1) {
                    this.$('.status').addClass('active');
                    this.$('.status .content').text(error_message);
                }
                else if (err_group.length > 1) {
                    this.$('.status').addClass('active');
                    this.$('.status .content').text("Click line number to see each error");
                }
            } else {
                new views.Modal(err_group[i]);
                break;
            }
        }
    } else {
        // will hit this if the server is offline and the user tries to save
        // We attach a error message to this resp object so that that the Modal can display it
        resp.err_message = 'Could not save project "' + model.id + '"';
        new views.Modal(resp);
    }
};

view.prototype.makeStylesheet = function(model) {
    if (!CodeMirror) throw new Error('CodeMirror not found.');
    var codeEl = this.$('.code').get(0),
        self = this,
        id = 'stylesheet-' + model.id.replace(/[\.]/g, '-');
    model.el = $(templates.ProjectStylesheet(model));
    model.codemirror = CodeMirror(codeEl, {<commit_msg>further improve carto error display<commit_after>view = Backbone.View.extend();

view.prototype.events = {
    'click .swatch': 'colorOpen',
    'click .swatch a[href=#save]': 'colorSave',
    'click .swatch a[href=#close]': 'colorClose',
    'click a.add': 'stylesheetAdd',
    'click a.icon': 'stylesheetDelete',
    'sortupdate .tabs': 'sortStylesheets',
    'click .status a[href=#close]': 'statusClose'
};

view.prototype.initialize = function() {
    _(this).bindAll(
        'render',
        'attach',
        'save',
        'error',
        'makeStylesheet',
        'stylesheetAdd',
        'stylesheetDelete',
        'sortStylesheets',
        'statusClose',
        'colors',
        'colorOpen',
        'colorSave',
        'colorClose'
    );
    this.model.bind('save', this.save);
    this.model.bind('saved', this.attach);
    this.model.bind('error', this.error);
    this.model.bind('poll', this.render);
    this.model.bind('poll', this.attach);
    this.render().attach();
};

view.prototype.render = function(init) {
    $(this.el).html(templates.Editor());
    this.model.get('Stylesheet').chain().each(this.makeStylesheet);
    this.$('.tabs').sortable({
        axis: 'x',
        containment: 'parent',
        tolerance: 'pointer'
    });
    return this;
};

view.prototype.attach = function() {
    this.statusClose();
    this.colors();
    return this;
};

view.prototype.save = function() {
    this.model.get('Stylesheet').forEach(function(model) {
        if (model.errors) {
            model.errors = [];
            for (i = 0; i < (model.codemirror.getValue().match(/\n/g)||[]).length+1; i++) {
                model.codemirror.clearMarker(i);
            }
        }
    });
    this.$('.tabs a.error').removeClass('error');
};

// Test for a Carto error of the form
//
//     style.mss:2 Invalid value for background-color ...
//
// and highlight the line number and stylesheet appropriately if
// found. Otherwise, display error in a modal.
view.prototype.error = function(model, resp) {
    if (resp.responseText) {
        // this assume Carto.js specific error array format response
        var err_message = JSON.parse(resp.responseText).message;
        var err_group = _(err_message.toString().split('\n')).compact();
        var lines = []
        for (var i = 0; i < err_group.length; i++) {
            var match = err_group[i].match(/^(Error: )?([\w.]+):([\d]+):([\d]+) (.*)$/);
            if (match) {
                var stylesheet = this.model.get('Stylesheet').get(match[2]),
                    id = 'stylesheet-' + stylesheet.id.replace(/[\.]/g, '-'),
                    lineNum = parseInt(match[3]) - 1;
                this.$('.tabs a[href=#' + id + ']').addClass('error');
                stylesheet.errors = stylesheet.errors || [];
                lines.push(lineNum+1);
                stylesheet.errors[lineNum] = match[5] + ' (line ' + (lineNum+1) + ')';
                stylesheet.codemirror.setMarker(lineNum, '%N%', 'error');
                if (err_group.length == 1) {
                    this.$('.status').addClass('active');
                    this.$('.status .content').text(stylesheet.errors[lineNum]);
                }
            } else {
                new views.Modal(err_group[i]);
                break;
            }
            if (lines.length > 1) {
                this.$('.status').addClass('active');
                this.$('.status .content').text("Click lines " + lines + " to see each error");
            }
        }
    } else {
        // will hit this if the server is offline and the user tries to save
        // We attach a error message to this resp object so that that the Modal can display it
        resp.err_message = 'Could not save project "' + model.id + '"';
        new views.Modal(resp);
    }
};

view.prototype.makeStylesheet = function(model) {
    if (!CodeMirror) throw new Error('CodeMirror not found.');
    var codeEl = this.$('.code').get(0),
        self = this,
        id = 'stylesheet-' + model.id.replace(/[\.]/g, '-');
    model.el = $(templates.ProjectStylesheet(model));
    model.codemirror = CodeMirror(codeEl, {
{'fraction_non_alphanumeric': 0.17369186046511628, 'fraction_numerical': 0.0030281007751937986, 'mean_word_length': 2.1455238095238096, 'pattern_counts': {'":': 0, '<': 7, '<?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': '5435627', 'n_tokens_mistral': 2489, 'n_tokens_neox': 2449, 'n_words': 519}