<commit_before>/**
 * Module dependencies.
 */

var $ = require('jquery')
var EventEmitter = require('events').EventEmitter
var inherits = require('util').inherits
var Template = require('./Template')
var utils = require('./utils')

/**
 * Expose `View`.
 */

module.exports = View

/**
 * Cache object for templates.
 */

var cache = {}

/**
 * Default options.
 */

View.defaults = {
  state: {},
  template: '',
  templateUrl: '',
  beforeRender: $.noop,
  afterRender: $.noop,
  events: null
}

/**
 * View constructor.
 * @constructor
 * @param {jQuery Element} $el
 * @param {Object} options
 * @emits `template loaded`
 */

function View ($el, options) {
  var self = this
  this.$el = $el
  this._options = $.extend({}, View.defaults, options)
  this._getInitialState()

  $.each(this._options, function (key, option) {
    if (Object.keys(View.defaults).indexOf(key) !== -1) return
    self[key] = option
  })

  this.props = utils.getProps($el)
  this._directiveEvents = []

  this._getTemplate()
    .done(function (template) {
      self._templateSource = template
      self._template = new Template(template)
      self.emit('template loaded')
      self._start()
    })
    .fail(function (err) {
      console.error('Fail to load external template:', err)
    })
}

/**
 * Inherits `EventEmitter`.
 */

inherits(View, EventEmitter)

/**
 * Alias for `View.prototype`.
 */

var fn = View.prototype

/**
 * Get the initial state.
 * @method
 * @api private
 */

fn._getInitialState = function () {
  var state = this._options.state
  this._state = $.isFunction(state)
    ? state()
    : state
}

/**
 * Return the current state.
 * @method
 * @api public
 * @returns {Object} state
 */

fn.getState = function (obj) {
  return this._state
}

/**
 * Set the current state.
 * @method
 * @api public
 * @emits `state change`
 */

fn.setState = function (obj) {
  this._state = $.extend(this._state, obj)
  this.emit('state change', this.getState())
  return this
}

/**
 * Set the state from an Ajax request.
 * @method
 * @api public
 * @params {Object} conf
 * @returns {Promise}
 */

fn.setStateFromAjax = function (conf) {
  var self = this

  var defaults = {
    url: null,
    method: 'get',
    state: null,
    property: null,
    data: null
  }

  conf = $.extend({}, defaults, conf)

  var deferred = $.Deferred()

  $.ajax({
    url: conf.url,
    context: self,
    method: conf.method.toUpperCase(),
    data: conf.data,
    dataType: 'json'
  })
    .done(function (response) {
      if (conf.property) {
        response = response[conf.property]
      }

      if (conf.state) {
        var obj = {}
        obj[conf.state] = response
        this.setState(obj)
      } else {
        this.setState(response)
      }

      deferred.resolveWith(this)
    })
    .fail(function (err) {
      deferred.rejectWith(this, err)
    })

  return deferred.promise()
}

/**
 * Remove an object from an array in the state.
 * @method
 * @api public
 * @param {String} state property
 * @param {*} object you want to remove
 */

fn.removeFromState = function (prop, obj) {
  var state = this.getState()[prop]
  var index = state.indexOf(obj)
  if (index === -1) return
  state.splice(index, 1)
  var newState = {}
  newState[prop] = state
  this.setState(newState)
}

/**
 * Get the template string.
 * The priority for get the template code is:
 * 1. templateUrl
 * 2. template
 * 3. $el's html
 * @method
 * @api private
 * @returns {Promise}
 */

fn._getTemplate = function () {
  var options = this._options
  var $el = this.$el

  if (options.templateUrl) return this._getExternalTemplate()

  var deferred = $.Deferred()

  if (options.template) {<commit_msg>Add `insertIntoState` method<commit_after>/**
 * Module dependencies.
 */

var $ = require('jquery')
var EventEmitter = require('events').EventEmitter
var inherits = require('util').inherits
var Template = require('./Template')
var utils = require('./utils')

/**
 * Expose `View`.
 */

module.exports = View

/**
 * Cache object for templates.
 */

var cache = {}

/**
 * Default options.
 */

View.defaults = {
  state: {},
  template: '',
  templateUrl: '',
  beforeRender: $.noop,
  afterRender: $.noop,
  events: null
}

/**
 * View constructor.
 * @constructor
 * @param {jQuery Element} $el
 * @param {Object} options
 * @emits `template loaded`
 */

function View ($el, options) {
  var self = this
  this.$el = $el
  this._options = $.extend({}, View.defaults, options)
  this._getInitialState()

  $.each(this._options, function (key, option) {
    if (Object.keys(View.defaults).indexOf(key) !== -1) return
    self[key] = option
  })

  this.props = utils.getProps($el)
  this._directiveEvents = []

  this._getTemplate()
    .done(function (template) {
      self._templateSource = template
      self._template = new Template(template)
      self.emit('template loaded')
      self._start()
    })
    .fail(function (err) {
      console.error('Fail to load external template:', err)
    })
}

/**
 * Inherits `EventEmitter`.
 */

inherits(View, EventEmitter)

/**
 * Alias for `View.prototype`.
 */

var fn = View.prototype

/**
 * Get the initial state.
 * @method
 * @api private
 */

fn._getInitialState = function () {
  var state = this._options.state
  this._state = $.isFunction(state)
    ? state()
    : state
}

/**
 * Return the current state.
 * @method
 * @api public
 * @returns {Object} state
 */

fn.getState = function (obj) {
  return this._state
}

/**
 * Set the current state.
 * @method
 * @api public
 * @emits `state change`
 */

fn.setState = function (obj) {
  this._state = $.extend(this._state, obj)
  this.emit('state change', this.getState())
  return this
}

/**
 * Set the state from an Ajax request.
 * @method
 * @api public
 * @params {Object} conf
 * @returns {Promise}
 */

fn.setStateFromAjax = function (conf) {
  var self = this

  var defaults = {
    url: null,
    method: 'get',
    state: null,
    property: null,
    data: null
  }

  conf = $.extend({}, defaults, conf)

  var deferred = $.Deferred()

  $.ajax({
    url: conf.url,
    context: self,
    method: conf.method.toUpperCase(),
    data: conf.data,
    dataType: 'json'
  })
    .done(function (response) {
      if (conf.property) {
        response = response[conf.property]
      }

      if (conf.state) {
        var obj = {}
        obj[conf.state] = response
        this.setState(obj)
      } else {
        this.setState(response)
      }

      deferred.resolveWith(this)
    })
    .fail(function (err) {
      deferred.rejectWith(this, err)
    })

  return deferred.promise()
}

/**
 * Remove an object from an array in the state.
 * @method
 * @api public
 * @param {String} state property
 * @param {*} object you want to remove
 */

fn.removeFromState = function (prop, obj) {
  var state = this.getState()[prop]
  var index = state.indexOf(obj)
  if (index === -1) return
  state.splice(index, 1)
  var newState = {}
  newState[prop] = state
  this.setState(newState)
}

/**
 * Insert a new item into an array from the state.
 * @method
 * @api public
 * @param {String} state property
 * @param {*} item
 */

fn.insertIntoState = function (prop, item) {
  var state = this.getState()[prop]
  state.push(item)
  var newState = {}
  newState[prop] = state
  this.setState()
}

/**
 * Get the template string.
 * The priority for get the template code is:
 * 1. templateUrl
 * 2. template
 * 3. $el's html
 * @method
 * @api private
 * @returns {Promise}
 */

fn._getTemplate = function () {
  var options = this._options
  var $el = this.$el

  if (options.templateUrl) return this._getExternalTemplate()

  var deferred = $.Deferred()

  if (options.template) {
{'fraction_non_alphanumeric': 0.1538761706555671, 'fraction_numerical': 0.0015608740894901144, 'mean_word_length': 2.834912718204489, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '45780', 'n_tokens_mistral': 2527, 'n_tokens_neox': 2501, 'n_words': 668}