<commit_before>var $ = require('jquery-browserify');
var _ = require('underscore');
var queue = require('queue-async');
var jsyaml = require('js-yaml');
var patch = require('../../vendor/liquid.patch');

var ModalView = require('./modal');
var key = require('keymaster');
var marked = require('marked');
var diff = require('diff');
var Backbone = require('backbone');
var File = require('../models/file');
var HeaderView = require('./header');
var ToolbarView = require('./toolbar');
var MetadataView = require('./metadata');
var auth = require('../config');
var util = require('../util');
var upload = require('../upload');
var cookie = require('../cookie');
var templates = require('../../dist/templates');

module.exports = Backbone.View.extend({
  id: 'post',

  template: templates.file,

  subviews: {},

  initialize: function(options) {
    _.bindAll(this);

    var app = options.app;
    app.loader.start();

    // Patch Liquid
    patch.apply(this);

    this.app = app;
    this.branch = options.branch || options.repo.get('master_branch');
    this.branches = options.branches;
    this.mode = options.mode;
    this.nav = options.nav;
    this.path = options.path || '';
    this.repo = options.repo;
    this.router = options.router;
    this.sidebar = options.sidebar;

    // Set the active nav element established by this.mode
    this.nav.setFileState(this.mode);

    // Events from vertical nav
    this.listenTo(this.nav, 'edit', this.edit);
    this.listenTo(this.nav, 'blob', this.blob);
    this.listenTo(this.nav, 'meta', this.meta);
    this.listenTo(this.nav, 'settings', this.settings);
    this.listenTo(this.nav, 'save', this.showDiff);

    // Events from sidebar
    this.listenTo(this.sidebar, 'destroy', this.destroy);
    this.listenTo(this.sidebar, 'draft', this.draft);
    this.listenTo(this.sidebar, 'cancel', this.cancel);
    this.listenTo(this.sidebar, 'confirm', this.updateFile);
    this.listenTo(this.sidebar, 'translate', this.translate);

    // Stash editor and metadataEditor content to sessionStorage on pagehide event
    this.listenTo($(window), 'pagehide', this.stashFile);

    // Prevent exit when there are unsaved changes
    // jQuery won't bind to 'beforeunload' event
    // e.returnValue for Firefox compatibility
    // https://developer.mozilla.org/en-US/docs/Web/Reference/Events/beforeunload
    window.onbeforeunload = (function(e) {
      if (this.dirty) {
        var message = t('actions.unsaved');
        (e || window.event).returnValue = message;

        return message;
      }
    }).bind(this);

    this.branches.fetch({
      success: this.setCollection,
      error: (function(model, xhr, options) {
        this.router.error(xhr);
      }).bind(this),
      complete: app.loader.done
    });
  },

  setCollection: function(collection, res, options) {
    this.app.loader.start();

    this.collection = collection.findWhere({ name: this.branch }).files;
    this.collection.fetch({
      success: this.setModel,
      error: (function(model, xhr, options) {
        this.router.error(xhr);
      }).bind(this),
      complete: this.app.loader.done,
      args: arguments
    });
  },

  setModel: function(model, res, options) {
    this.app.loader.start();

    // Set default metadata from collection
    var defaults = this.collection.defaults;
    var path;

    // Set model either by calling directly for new File models
    // or by filtering collection for existing File models
    switch(this.mode) {
      case 'edit':
      case 'blob':
      case 'preview':
        this.model = this.collection.findWhere({ path: this.path });
        break;
      case 'new':
        this.model = new File({
          branch: this.branches.findWhere({ name: this.branch }),
          collection: this.collection,
          path: this.path,
          repo: this.repo
        });
        break;
    }

    if (this.model) {
      if (defaults) {
        path = this.nearestPath(this.model.get('path'), defaults);
        this.model.set('defaults', defaults[path]);
      }

      // Render on complete to render even if model does not exist on remote yet
      this.model.fetch({
        complete: (function() {
          this.app.loader.done();
          this.render();
        }).bind(this)
      });
    } else {
      this.router.notify(
        t('notification.error.exists'),
        undefined,
        [
          {
            'title': t('notification.create'),
            'className': 'create',
            'link': '#'
          },
          {
            'title': t('notification.back'),
            'link': '#' + _.compact([
              this.repo.get('owner').login,
              this.repo.get('name'),
              'tree',
              this.branch,
              util.extractFilename(this.path)[0]
            ]).join('/')
          }
        ]
      );

      this.app.loader.done();
    }
  },

  nearestPath: function(path, defaults) {
    // Match nearest parent directory default metadata
    // Match paths in _drafts to corresponding defaults set at _posts
    path = path.replace(/^(_drafts)/, '_posts');
    var nearestDir = /\/?(?!.*\/).*$/;

    while (!_.has(defaults, path) && nearestDir.test(path)) {
      path = path.replace( nearestDir, '' );
    }

    return path;
  },

  cursor: function() {
    var view = this;
    var selection = util.trim(this.editor.getSelection());

    var match = {
      lineBreak: /\n/,
      h1: /^#{1}/,
      h2: /^#{2}/,
      h3: /^#{3}/,
      h4: /^#{4}/,
      strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,<commit_msg>fix bug: "freezes when click 'draft to post'"<commit_after>var $ = require('jquery-browserify');
var _ = require('underscore');
var queue = require('queue-async');
var jsyaml = require('js-yaml');
var patch = require('../../vendor/liquid.patch');

var ModalView = require('./modal');
var key = require('keymaster');
var marked = require('marked');
var diff = require('diff');
var Backbone = require('backbone');
var File = require('../models/file');
var HeaderView = require('./header');
var ToolbarView = require('./toolbar');
var MetadataView = require('./metadata');
var auth = require('../config');
var util = require('../util');
var upload = require('../upload');
var cookie = require('../cookie');
var templates = require('../../dist/templates');

module.exports = Backbone.View.extend({
  id: 'post',

  template: templates.file,

  subviews: {},

  initialize: function(options) {
    _.bindAll(this);

    var app = options.app;
    app.loader.start();

    // Patch Liquid
    patch.apply(this);

    this.app = app;
    this.branch = options.branch || options.repo.get('master_branch');
    this.branches = options.branches;
    this.mode = options.mode;
    this.nav = options.nav;
    this.path = options.path || '';
    this.repo = options.repo;
    this.router = options.router;
    this.sidebar = options.sidebar;

    // Set the active nav element established by this.mode
    this.nav.setFileState(this.mode);

    // Events from vertical nav
    this.listenTo(this.nav, 'edit', this.edit);
    this.listenTo(this.nav, 'blob', this.blob);
    this.listenTo(this.nav, 'meta', this.meta);
    this.listenTo(this.nav, 'settings', this.settings);
    this.listenTo(this.nav, 'save', this.showDiff);

    // Events from sidebar
    this.listenTo(this.sidebar, 'destroy', this.destroy);
    this.listenTo(this.sidebar, 'draft', this.draft);
    this.listenTo(this.sidebar, 'cancel', this.cancel);
    this.listenTo(this.sidebar, 'confirm', this.updateFile);
    this.listenTo(this.sidebar, 'translate', this.translate);

    // Stash editor and metadataEditor content to sessionStorage on pagehide event
    this.listenTo($(window), 'pagehide', this.stashFile);

    // Prevent exit when there are unsaved changes
    // jQuery won't bind to 'beforeunload' event
    // e.returnValue for Firefox compatibility
    // https://developer.mozilla.org/en-US/docs/Web/Reference/Events/beforeunload
    window.onbeforeunload = (function(e) {
      if (this.dirty) {
        var message = t('actions.unsaved');
        (e || window.event).returnValue = message;

        return message;
      }
    }).bind(this);

    this.branches.fetch({
      success: this.setCollection,
      error: (function(model, xhr, options) {
        this.router.error(xhr);
      }).bind(this),
      complete: app.loader.done
    });
  },

  setCollection: function(collection, res, options) {
    this.app.loader.start();

    this.collection = collection.findWhere({ name: this.branch }).files;
    this.collection.fetch({
      success: this.setModel,
      error: (function(model, xhr, options) {
        this.router.error(xhr);
      }).bind(this),
      complete: this.app.loader.done,
      args: arguments
    });
  },

  setModel: function(model, res, options) {
    this.app.loader.start();

    // Set default metadata from collection
    var defaults = this.collection.defaults;
    var path;

    // Set model either by calling directly for new File models
    // or by filtering collection for existing File models
    switch(this.mode) {
      case 'edit':
      case 'blob':
      case 'preview':
        this.model = this.collection.findWhere({ path: this.path });
        break;
      case 'new':
        this.model = new File({
          branch: this.branches.findWhere({ name: this.branch }),
          collection: this.collection,
          path: this.path,
          repo: this.repo
        });
        break;
    }

    if (this.model) {
      if (defaults) {
        path = this.nearestPath(this.model.get('path'), defaults);
        this.model.set('defaults', defaults[path]);
      }

      // Render on complete to render even if model does not exist on remote yet
      this.model.fetch({
        complete: (function() {
          this.app.loader.done();
          this.render();
        }).bind(this)
      });
    } else {
      this.router.notify(
        t('notification.error.exists'),
        undefined,
        [
          {
            'title': t('notification.create'),
            'className': 'create',
            'link': '#'
          },
          {
            'title': t('notification.back'),
            'link': '#' + _.compact([
              this.repo.get('owner').login,
              this.repo.get('name'),
              'tree',
              this.branch,
              util.extractFilename(this.path)[0]
            ]).join('/')
          }
        ]
      );

      this.app.loader.done();
    }
  },

  nearestPath: function(path, defaults) {
    // Match nearest parent directory default metadata
    // Match paths in _drafts to corresponding defaults set at _posts
    path = path.replace(/^(_drafts)/, '_posts');
    var nearestDir = /\/?(?!.*\/).*$/;

    while (!_.has(defaults, path) && nearestDir.test(path) && path) {
      path = path.replace( nearestDir, '' );
    }

    return path;
  },

  cursor: function() {
    var view = this;
    var selection = util.trim(this.editor.getSelection());

    var match = {
      lineBreak: /\n/,
      h1: /^#{1}/,
      h2: /^#{2}/,
      h3: /^#{3}/,
      h4: /^#{4}/,
      strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
{'fraction_non_alphanumeric': 0.1655658693323813, 'fraction_numerical': 0.0016065690824705462, 'mean_word_length': 2.430802204531537, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, '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': '3694436', 'n_tokens_mistral': 3396, 'n_tokens_neox': 3319, 'n_words': 767}