<commit_before>!function(__global__, server) {

var DOMBuilder = (server ? require('DOMBuilder') : __global__.DOMBuilder)
  , Sacrum = (server ? require('./sacrum') : __global__.Sacrum)
  , extend = Sacrum.util.extend, format = Sacrum.util.format
  , Views = Sacrum.Views
  , patterns = Sacrum.patterns, url = Sacrum.url, reverse = Sacrum.reverse

// ============================================================= Admin Views ===

/**
 * Views which use created ModelAdminView instances to display an admin section.
 */
var AdminViews = new Views({
  name: 'AdminViews'
, elementId: 'admin'

  /** ModelAdminViews which have been registered for display. */
, modelViews: []

, init: function() {
    this.log('init')
    if (!server) {
      this.el = document.getElementById(this.elementId)
    }

    // Hook ap all ModelAdminViews which have been created
    for (var i = 0, l = ModelAdminViews.instances.length; i < l; i++) {
      var mv = ModelAdminViews.instances[i]
      // Give all instances our element to display their content in
      mv.el = this.el
      this.modelViews.push(mv)
    }
  }

  /**
   * Lists registered ModelAdminViews.
   */
, index: function() {
    this.log('index')
    var models = []
    for (var i = 0, l = this.modelViews.length, mv; i < l; i++) {
      var mv = this.modelViews[i]
      models.push({
        name: mv.storage.model._meta.namePlural
      , listURL: reverse(mv.urlName('list'))
      })
    }
    return this.display('admin:index', {models: models})
  }

  /**
   * Creates a URL pattern for the index view and roots each ModelAdminViews
   * instance under a URL based on its namespace.
   */
, getURLs: function() {
    var urlPatterns = patterns(this
      , url('', 'index', 'admin_index')
      )
    for (var i = 0, l = this.modelViews.length; i < l; i++) {
      var mv = this.modelViews[i]
      urlPatterns.push( url(format('%s/', mv.namespace), mv.getURLs()) )
    }
    return urlPatterns
  }
})

// --------------------------------------------------------- ModelAdminViews ---

/**
 * Views which take care of some of the repetitive work involved in creating
 * basic CRUD functionality for a particular Model. This specialised version of
 * Views expects to find the following instance properties:
 *
 *    namespace
 *       Unique namespace for the instance - used in base CRUD templates to
 *       ensure created element ids are unique and when looking up templates
 *       which override the base templates.
 *
 *    storage
 *       A Storage object used to create, retrieve, update and delete Model
 *       instances.
 *
 *    form
 *       A Form used to take and validate user input when creating and updating
 *       Model instances.
 *
 *    elementId (Optional)
 *       The id of the elements in which content should be displayed, if
 *       appropriate.
 *
 * @constructor
 * @param {Object} props instance properties.
 */
var ModelAdminViews = Views.extend({
  constructor: function(props) {
    ModelAdminViews.instances.push(this)
    Views.call(this, props)
  }

, name: 'ModelAdminViews'

  /**
   * Overrides render to pass in template variables which are required for Admin
   * templates.
   */
, render: function(templateName, context, events) {
    extend(context, {
      ns: this.namespace
    , model: this.storage.model._meta
    })
    return ModelAdminViews.__super__.render.call(this, templateName, context, events)
  }

  /**
   * Finds the content element for this ModelAdminViews and displays a list of
   * Model instances by default.
   */
, init: function() {
    this.log('init')
    if (!server && this.elementId) {
      this.el = document.getElementById(this.elementId)
    }
  }

  /**
   * Constructs a URL name based on this ModenAdminViews' namespace.
   */
, urlName: function(name) {
    return 'admin_' + this.namespace + '_' + name
  }

  /**
   * Displays a list of Model instances.
   */
, list: function() {
    this.log('list')
    var items = this.storage.all()
    return this.display([this.namespace + ':admin:list', 'admin:list']
      , { items: items
        , rowTemplates: [this.namespace + ':admin:listRow', 'admin:listRow']
        , addURL: reverse(this.urlName('add'))
        }
      )
  }

  /**
   * Displays the selected Model's details.
   */
, detail: function(id) {
    this.log('detail', id)
    var item = this.storage.get(id)
    return this.display([this.namespace + ':admin:detail', 'admin:detail']
      , { item: item
        , editURL: reverse(this.urlName('edit'), [id])
        , deleteURL: reverse(this.urlName('delete'), [id])
        }
      )
  }

  /**
   * Displays the add Form, or validates user input and creates a new Model
   * instance or redisplays the form with errors if form data was given.
   */
, add: function(data) {
    this.log('add', data)
    var form
    if (data) {
      form = this.form({data: data})
      if (form.isValid()) {
        var instance = this.storage.add(form.cleanedData)
        return this.redirect(reverse(this.urlName('detail'), [instance.id]))
      }
      else if (!server) {
        // Look up the <tbody> containing the form rows and replace its contents
        // with the rendered invalid form.
        return this.replaceContents(format('%sFormBody', this.namespace),
                                    form.asTable())
      }
      // If we're on the server, fall through to rendering the complete template
    }
    else {
      form = this.form()
    }
    return this.display([this.namespace + ':admin:add', 'admin:add']
      , { form: form
        , submitURL: reverse(this.urlName('add'))
        , cancelURL: reverse(this.urlName('list'))
        }
      )
  }

  /**
   * Displays the edit Form, populated with the selected Model instance's data,
   * or validates user input and either updates the selected Model instance or
   * redisplays the form with errors if form data was given.
   */
, edit: function(id, data) {
    this.log('edit', id, data)<commit_msg>Admin should instantiate a Model instance before saving.<commit_after>!function(__global__, server) {

var DOMBuilder = (server ? require('DOMBuilder') : __global__.DOMBuilder)
  , Sacrum = (server ? require('./sacrum') : __global__.Sacrum)
  , extend = Sacrum.util.extend, format = Sacrum.util.format
  , Views = Sacrum.Views
  , patterns = Sacrum.patterns, url = Sacrum.url, reverse = Sacrum.reverse

// ============================================================= Admin Views ===

/**
 * Views which use created ModelAdminView instances to display an admin section.
 */
var AdminViews = new Views({
  name: 'AdminViews'
, elementId: 'admin'

  /** ModelAdminViews which have been registered for display. */
, modelViews: []

, init: function() {
    this.log('init')
    if (!server) {
      this.el = document.getElementById(this.elementId)
    }

    // Hook ap all ModelAdminViews which have been created
    for (var i = 0, l = ModelAdminViews.instances.length; i < l; i++) {
      var mv = ModelAdminViews.instances[i]
      // Give all instances our element to display their content in
      mv.el = this.el
      this.modelViews.push(mv)
    }
  }

  /**
   * Lists registered ModelAdminViews.
   */
, index: function() {
    this.log('index')
    var models = []
    for (var i = 0, l = this.modelViews.length, mv; i < l; i++) {
      var mv = this.modelViews[i]
      models.push({
        name: mv.storage.model._meta.namePlural
      , listURL: reverse(mv.urlName('list'))
      })
    }
    return this.display('admin:index', {models: models})
  }

  /**
   * Creates a URL pattern for the index view and roots each ModelAdminViews
   * instance under a URL based on its namespace.
   */
, getURLs: function() {
    var urlPatterns = patterns(this
      , url('', 'index', 'admin_index')
      )
    for (var i = 0, l = this.modelViews.length; i < l; i++) {
      var mv = this.modelViews[i]
      urlPatterns.push( url(format('%s/', mv.namespace), mv.getURLs()) )
    }
    return urlPatterns
  }
})

// --------------------------------------------------------- ModelAdminViews ---

/**
 * Views which take care of some of the repetitive work involved in creating
 * basic CRUD functionality for a particular Model. This specialised version of
 * Views expects to find the following instance properties:
 *
 *    namespace
 *       Unique namespace for the instance - used in base CRUD templates to
 *       ensure created element ids are unique and when looking up templates
 *       which override the base templates.
 *
 *    storage
 *       A Storage object used to create, retrieve, update and delete Model
 *       instances.
 *
 *    form
 *       A Form used to take and validate user input when creating and updating
 *       Model instances.
 *
 *    elementId (Optional)
 *       The id of the elements in which content should be displayed, if
 *       appropriate.
 *
 * @constructor
 * @param {Object} props instance properties.
 */
var ModelAdminViews = Views.extend({
  constructor: function(props) {
    ModelAdminViews.instances.push(this)
    Views.call(this, props)
  }

, name: 'ModelAdminViews'

  /**
   * Overrides render to pass in template variables which are required for Admin
   * templates.
   */
, render: function(templateName, context, events) {
    extend(context, {
      ns: this.namespace
    , model: this.storage.model._meta
    })
    return ModelAdminViews.__super__.render.call(this, templateName, context, events)
  }

  /**
   * Finds the content element for this ModelAdminViews and displays a list of
   * Model instances by default.
   */
, init: function() {
    this.log('init')
    if (!server && this.elementId) {
      this.el = document.getElementById(this.elementId)
    }
  }

  /**
   * Constructs a URL name based on this ModenAdminViews' namespace.
   */
, urlName: function(name) {
    return 'admin_' + this.namespace + '_' + name
  }

  /**
   * Displays a list of Model instances.
   */
, list: function() {
    this.log('list')
    var items = this.storage.all()
    return this.display([this.namespace + ':admin:list', 'admin:list']
      , { items: items
        , rowTemplates: [this.namespace + ':admin:listRow', 'admin:listRow']
        , addURL: reverse(this.urlName('add'))
        }
      )
  }

  /**
   * Displays the selected Model's details.
   */
, detail: function(id) {
    this.log('detail', id)
    var item = this.storage.get(id)
    return this.display([this.namespace + ':admin:detail', 'admin:detail']
      , { item: item
        , editURL: reverse(this.urlName('edit'), [id])
        , deleteURL: reverse(this.urlName('delete'), [id])
        }
      )
  }

  /**
   * Displays the add Form, or validates user input and creates a new Model
   * instance or redisplays the form with errors if form data was given.
   */
, add: function(data) {
    this.log('add', data)
    var form
    if (data) {
      form = this.form({data: data})
      if (form.isValid()) {
        var instance = this.storage.add(new this.storage.model(form.cleanedData))
        return this.redirect(reverse(this.urlName('detail'), [instance.id]))
      }
      else if (!server) {
        // Look up the <tbody> containing the form rows and replace its contents
        // with the rendered invalid form.
        return this.replaceContents(format('%sFormBody', this.namespace),
                                    form.asTable())
      }
      // If we're on the server, fall through to rendering the complete template
    }
    else {
      form = this.form()
    }
    return this.display([this.namespace + ':admin:add', 'admin:add']
      , { form: form
        , submitURL: reverse(this.urlName('add'))
        , cancelURL: reverse(this.urlName('list'))
        }
      )
  }

  /**
   * Displays the edit Form, populated with the selected Model instance's data,
   * or validates user input and either updates the selected Model instance or
   * redisplays the form with errors if form data was given.
   */
, edit: function(id, data) {
    this.log('edit', id, data)
{'fraction_non_alphanumeric': 0.13967594515995013, 'fraction_numerical': 0.0004985459077690071, 'mean_word_length': 2.6100779844031194, 'pattern_counts': {'":': 0, '<': 11, '<?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': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1604123', 'n_tokens_mistral': 3543, 'n_tokens_neox': 3458, 'n_words': 1077}