You are here

editor_note.module in Editor Notes 7

Same filename and directory in other branches
  1. 8 editor_note.module

Main functionality for Editor Notes module.

File

editor_note.module
View source
<?php

/**
 * @file
 * Main functionality for Editor Notes module.
 */
define('EDITOR_NOTE_DEFAULT_TEXT_FORMAT', 'plain_text');

/**
 * Implements hook_help().
 */
function editor_note_help($path) {
  if ($path == 'admin/help#editor_note') {
    $output = '<h3>' . t('About') . '</h3>';
    $output .= '<p>' . t('The modules improves administration/editorial usability and provides configurable "Editor Notes" field, which can be added to any Drupal entity.') . '</p>';
    $output .= '<p>' . t('Concept of "Editor Notes" is similar to "Comments". The main difference is that "Editor Notes" are for editors and admins rather than for end users.') . '</p>';
    $output .= '<h3>' . t('Usage') . '</h3>';
    $usage = array(
      t('As website editor I can write status notes to myself and other editors working on the same material.'),
      t('The module provides "Editor Notes" field available on "Manage Fields" page.'),
      t('This field can also be added to any Drupal fieldable entity (user etc).'),
      t('List of previously added notes displays in "content edit" form in configurable table.'),
      t('Notes can also be displayed for the end user in configurable table if necessary.'),
      t('When editor opens "content add" form for the first time he sees a field (textarea) providing him an option to add the first note.'),
      t('When editor opens "content edit" form he sees "Editor Notes" widget with already added notes if any found.'),
    );
    $output .= theme('item_list', array(
      'items' => $usage,
    ));
    $output .= '<h3>' . t('Features') . '</h3>';
    $features = array(
      t('Website editor can only add / update / delete his own notes by default.'),
      t('However notes may also be updated or removed by any user with "Administer any editor note" permission.'),
      t('CRUD operations on notes support Ajax and perform in configurable modal window without page reload.'),
      t('Module supports Views, content revisions and content translation.'),
    );
    $output .= theme('item_list', array(
      'items' => $features,
    ));
    $output .= '<h3>' . t('Similar Projects') . '</h3>';
    $output .= '<p><strong>' . t('The key feature of the Editor Notes module is that editor is able to browse (add/update/remove) notes directly in "edit content" form.') . '</strong></p>';
    $output .= '<p>' . t('It helps to save time when adding/updating large amount of content.') . '</p>';
    $projects = array(
      t('!module creates a block that displays a textarea pre-filled with the existing comment for that specific page.', array(
        '!module' => l(t('Admin Notes'), 'https://www.drupal.org/project/admin_notes'),
      )),
      t('!module introduces a new content type "sitenotes." It also creates a menu item in the Admin >> Site building menu, where it is available only to privileged users.', array(
        '!module' => l(t('SiteNotes'), 'https://www.drupal.org/project/sitenotes'),
      )),
      t('!module consist of titles and text rendered into a block. The notes are specific to each authenticated user and can only be viewed by the user who created them.', array(
        '!module' => l(t('Personal Notes'), 'https://www.drupal.org/project/personal_notes'),
      )),
      t('!module creates a block with the ability to add, delete and edit notes. Notes are stored on a per path basis and the block can be made visible to certain roles/paths.', array(
        '!module' => l(t('Stickynote'), 'https://www.drupal.org/project/stickynote'),
      )),
    );
    $output .= theme('item_list', array(
      'items' => $projects,
    ));
    $output .= '<p>' . t('The difference from mentioned above modules is that Editor Notes creates configurable ajaxified field (instead of blocks or content type).') . '</p>';
    $output .= '<p>' . t('Field can be attached to an entity and associated with that entity. Each field item controls CRUD operations based on authorship (like Comment module).') . '</p>';
    $output .= '<h3>' . t('Requirements') . '</h3>';
    $requirements = array(
      l(t('Chaos tool suite'), 'https://www.drupal.org/project/ctools'),
      l(t('Entity API'), 'https://www.drupal.org/project/entity'),
    );
    $output .= theme('item_list', array(
      'items' => $requirements,
    ));
    $output .= '<h3>' . t('Installation') . '</h3>';
    $installation = array(
      t('Drop the entire Editor Note module into your "sites/all/modules" folder.'),
      t('Enable the module from the !page.', array(
        '!page' => l(t('modules page'), 'admin/modules'),
      )),
      t('Create new or edit existing content type and add a new field of type "Editor Notes".'),
    );
    $output .= theme('item_list', array(
      'items' => $installation,
      'type' => 'ol',
    ));
    $output .= '<h3>' . t('Sponsorship') . '</h3>';
    $credit = array(
      l(t('EPAM Systems'), 'https://www.drupal.org/node/2114867'),
      l(t('NBC Universal'), 'http://www.nbcuni.com'),
    );
    $output .= '<p>' . t('This project was sponsored by') . ':</p>';
    $output .= theme('item_list', array(
      'items' => $credit,
    ));
    $output .= '<h3>' . t('Acknowledgments') . '</h3>';
    $output .= '<p>' . t('Special thanks to !username1 and !username2 for reviewing the module.', array(
      '!username1' => l(t('Sergei Churilo'), 'https://www.drupal.org/user/584658'),
      '!username2' => l(t('Alexey Yahnenko'), 'https://www.drupal.org/user/2635711'),
    )) . '</p>';
    $output .= '<h3>' . t('Author') . '</h3>';
    $output .= '<p>' . l(t('Rostislav Sergeenkov'), 'https://www.drupal.org/u/rostislav-sergeenkov') . '</p>';
    return $output;
  }
}

/**
 * Implements hook_menu().
 */
function editor_note_menu() {
  $items['editor_note/edit/%ctools_js/%/%'] = array(
    'title' => 'Update note',
    'page arguments' => array(
      2,
      4,
    ),
    'page callback' => 'editor_note_confirm_edit_page',
    'access callback' => 'editor_note_access_crud_operations',
    'access arguments' => array(
      3,
      4,
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'editor_note.pages.inc',
    'theme callback' => 'ajax_base_page_theme',
  );
  $items['editor_note/remove/%ctools_js/%/%'] = array(
    'title' => 'Remove note',
    'page arguments' => array(
      2,
      4,
    ),
    'page callback' => 'editor_note_confirm_remove_page',
    'access callback' => 'editor_note_access_crud_operations',
    'access arguments' => array(
      3,
      4,
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'editor_note.pages.inc',
    'theme callback' => 'ajax_base_page_theme',
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function editor_note_permission() {
  return array(
    'administer any editor note' => array(
      'title' => t('Administer any editor note'),
    ),
  );
}

/**
 * Implements hook_theme().
 */
function editor_note_theme() {
  return array(
    'editor_note_message' => array(
      'variables' => array(
        'field_name' => NULL,
        'message_text' => NULL,
        'message_type' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_entity_info().
 */
function editor_note_entity_info() {
  $entity = array(
    'editor_note' => array(
      'label' => t('Editor Note'),
      'entity class' => 'Entity',
      'controller class' => 'EntityAPIController',
      'views controller class' => 'EntityDefaultViewsController',
      'base table' => 'editor_note',
      'fieldable' => FALSE,
      'entity keys' => array(
        'id' => 'id',
      ),
      'module' => 'editor_note',
    ),
  );
  return $entity;
}

/**
 * Implements hook_entity_property_info().
 */
function editor_note_entity_property_info() {
  $properties = array(
    'id' => array(
      'type' => 'integer',
      'label' => t('Editor Note ID'),
      'description' => t('Unique editor note ID.'),
      'schema field' => 'id',
    ),
    'note' => array(
      'type' => 'text',
      'label' => t('Editor Note'),
      'description' => t('Content of editor note.'),
      'schema field' => 'note',
    ),
    'entity_type' => array(
      'type' => 'text',
      'label' => t('Entity Type'),
      'description' => t('The entity type editor note is attached to.'),
      'schema field' => 'entity_type',
    ),
    'bundle' => array(
      'type' => 'text',
      'label' => t('Bundle'),
      'description' => t('The bundle of the entity editor note is attached to.'),
      'schema field' => 'bundle',
    ),
    'field_name' => array(
      'type' => 'text',
      'label' => t('Field Name'),
      'description' => t('The field name of the field containing editor note.'),
      'schema field' => 'field_name',
    ),
    'entity_id' => array(
      'type' => 'integer',
      'label' => t('Entity ID'),
      'description' => t('The entity id editor note is attached to.'),
      'schema field' => 'entity_id',
    ),
    'revision_id' => array(
      'type' => 'integer',
      'label' => t('Revision ID'),
      'description' => t('The entity revision editor note is attached to.'),
      'schema field' => 'revision_id',
    ),
    'uid' => array(
      'type' => 'integer',
      'label' => t('Updated by UID'),
      'description' => t('The unique ID of the user who last updated editor note.'),
      'schema field' => 'uid',
    ),
    'created' => array(
      'type' => 'date',
      'label' => t('Created'),
      'description' => t('The timestamp that the note was created.'),
      'schema field' => 'created',
    ),
    'changed' => array(
      'type' => 'date',
      'label' => t('Changed'),
      'description' => t('The timestamp that the note was last updated.'),
      'schema field' => 'changed',
    ),
    'text_format' => array(
      'type' => 'text',
      'label' => t('Text Format'),
      'description' => t('The text format of an editor note.'),
      'schema field' => 'text_format',
    ),
  );
  $info['editor_note']['properties'] = $properties;
  return $info;
}

/**
 * Implements hook_views_data_alter().
 */
function editor_note_views_data_alter(&$data) {

  // Exposes uid as a relationship to users.
  $data['editor_note']['author_info'] = array(
    'title' => t('User information.'),
    'help' => t('Information related to user who authored/updated the note.'),
    'relationship' => array(
      'base' => 'users',
      'base field' => 'uid',
      'relationship field' => 'uid',
      'handler' => 'views_handler_relationship',
      'label' => t('User information.'),
    ),
  );

  // Expose entity_id as a relationship to node (the most common use case).
  $data['editor_note']['node_info'] = array(
    'title' => t('Node information.'),
    'help' => t('Related node object.'),
    'relationship' => array(
      'base' => 'node',
      'base field' => 'nid',
      'relationship field' => 'entity_id',
      'handler' => 'views_handler_relationship',
      'label' => t('Node information.'),
    ),
  );
}

/**
 * Implements hook_entity_delete().
 */
function editor_note_entity_delete($entity, $type) {
  list($entity_id) = entity_extract_ids($type, $entity);

  // Removes notes from editor notes table.
  db_delete('editor_note')
    ->condition('entity_type', $type)
    ->condition('entity_id', $entity_id)
    ->execute();
}

/**
 * Implements hook_node_revision_delete().
 */
function editor_note_node_revision_delete($node) {

  // Removes notes from editor notes table.
  db_delete('editor_note')
    ->condition('entity_type', 'node')
    ->condition('entity_id', $node->nid)
    ->condition('revision_id', $node->vid)
    ->execute();
}

/**
 * Implements hook_field_delete_instance().
 */
function editor_note_field_delete_instance($instance) {

  // Removes notes from editor notes table.
  db_delete('editor_note')
    ->condition('entity_type', $instance['entity_type'])
    ->condition('bundle', $instance['bundle'])
    ->condition('field_name', $instance['field_name'])
    ->execute();
}

/**
 * Implements hook_field_info().
 */
function editor_note_field_info() {
  return array(
    'editor_note' => array(
      'label' => t('Editor Notes'),
      'description' => t('Field for taking editor notes.'),
      'settings' => array(
        'notes_permissions' => 'default',
        'notes_size' => 5,
        'notes_placeholder' => t('Create a note'),
        'notes_maxlength' => 0,
        'limit' => 10,
        'order' => 'DESC',
        'display' => 1,
        'text_processing' => EDITOR_NOTE_DEFAULT_TEXT_FORMAT,
        'pager' => array(
          'enabled' => 1,
          'pager_below' => 1,
        ),
        'modal' => array(
          'overlay' => array(
            'opacity' => 0.7,
            'bgcolor' => '000000',
          ),
          'edit' => array(
            'width' => 600,
            'height' => 'auto',
          ),
          'remove' => array(
            'width' => 320,
            'height' => 'auto',
          ),
        ),
      ),
      'instance_settings' => array(),
      'default_widget' => 'editor_note_field_widget',
      'default_formatter' => 'editor_note_field_formatter',
    ),
  );
}

/**
 * Implements hook_field_is_empty().
 *
 * Defines whether to save field value to the database.
 */
function editor_note_field_is_empty($item, $field) {
  if ($field['type'] == 'editor_note') {
    if (is_array($item['note'])) {
      return empty($item['note']['value']);
    }
    else {
      return empty($item['note']);
    }
  }
}

/**
 * Implements hook_field_settings_form().
 *
 * Creates field settings form.
 */
function editor_note_field_settings_form($field, $instance, $has_data) {
  $settings = $field['settings'];
  $form['notes_display_mode'] = array(
    '#type' => 'radios',
    '#title' => t('Display mode'),
    '#required' => TRUE,
    '#description' => t('"Display list of notes per entity revision" means separate list of notes for each revision while "Display list of notes per entity" displays combined list of notes for all revisions.'),
    '#default_value' => isset($settings['notes_display_mode']) ? $settings['notes_display_mode'] : 'per_revision',
    '#options' => array(
      'per_revision' => t('Display list of notes per entity revision'),
      'per_entity' => t('Display list of notes per entity'),
    ),
  );
  $form['notes_permissions'] = array(
    '#type' => 'radios',
    '#title' => t('Field-level permissions'),
    '#required' => TRUE,
    '#description' => t('"Default" mode means configuring "Administer any editor note" permission on !permissions page while "Create only" mode can be used to prevent ability to update or edit notes.', array(
      '!permissions' => l(t('Permissions'), 'admin/people/permissions'),
    )),
    '#default_value' => isset($settings['notes_permissions']) ? $settings['notes_permissions'] : 'default',
    '#options' => array(
      'default' => t('Default'),
      'create_only' => t('Create only'),
    ),
  );
  $form['notes_size'] = array(
    '#type' => 'textfield',
    '#title' => t('Size of Notes field (rows)'),
    '#default_value' => $settings['notes_size'],
    '#required' => TRUE,
    '#description' => t('Specify the visible number of lines in textarea for adding note.'),
    '#element_validate' => array(
      'element_validate_integer_positive',
    ),
  );
  $form['notes_placeholder'] = array(
    '#type' => 'textfield',
    '#title' => t('Placeholder for blank Notes field'),
    '#default_value' => $settings['notes_placeholder'],
    '#required' => FALSE,
    '#description' => t('Specifies a short hint that describes the expected value of the textarea.'),
  );
  $form['limit'] = array(
    '#type' => 'textfield',
    '#title' => t('Display a specified number of items.'),
    '#default_value' => $settings['limit'],
    '#required' => TRUE,
    '#description' => t('Display a specified number of items. Set 0 for no limit.'),
    '#element_validate' => array(
      'editor_note_validate_integer_positive_or_zero',
    ),
  );
  $form['text_processing'] = array(
    '#type' => 'radios',
    '#title' => t('Text processing'),
    '#default_value' => isset($settings['text_processing']) ? $settings['text_processing'] : EDITOR_NOTE_DEFAULT_TEXT_FORMAT,
    '#options' => array(
      'plain_text' => t('Plain text'),
      'filtered_text' => t('Filtered text (user selects text format)'),
    ),
  );
  $form['notes_maxlength'] = array(
    '#type' => 'textfield',
    '#title' => t('Maximum number of characters user can enter'),
    '#default_value' => $settings['notes_maxlength'],
    '#required' => TRUE,
    '#description' => t('Specifies the maximum number of characters allowed in the textarea. Set 0 for no limit. This makes sense for "Plain text" text format only!'),
    '#element_validate' => array(
      'editor_note_validate_integer_positive_or_zero',
    ),
    '#states' => array(
      'invisible' => array(
        'input[name="field[settings][text_processing]"]' => array(
          'value' => 'filtered_text',
        ),
      ),
    ),
  );
  $form['order'] = array(
    '#type' => 'radios',
    '#title' => t('Notes ordering'),
    '#options' => array(
      'DESC' => t('Display recently updated notes first'),
      'ASC' => t('Display recently updated notes last'),
    ),
    '#default_value' => $settings['order'],
    '#description' => t('Set order of notes in the table.'),
  );
  $form['display'] = array(
    '#type' => 'checkbox',
    '#title' => t('Textarea above notes table'),
    '#default_value' => $settings['display'],
    '#description' => t('Display "Create a note" field above the notes table. Otherwise it will be shown below the notes table.'),
  );
  $form['pager'] = array(
    '#type' => 'fieldset',
    '#title' => t('Pagination'),
    '#collapsed' => FALSE,
    '#collapsible' => FALSE,
    '#states' => array(
      'invisible' => array(
        'input[name="field[settings][limit]"]' => array(
          'value' => 0,
        ),
      ),
    ),
  );
  $form['pager']['enabled'] = array(
    '#type' => 'checkbox',
    '#title' => t('Enable pagination'),
    '#default_value' => $settings['pager']['enabled'],
    '#description' => t('Whether to display pagination if number of notes added is greater that can be displayed.'),
  );
  $form['pager']['pager_below'] = array(
    '#type' => 'checkbox',
    '#title' => t('Pagination below notes table'),
    '#default_value' => $settings['pager']['pager_below'],
    '#description' => t('Displays pagination below the notes table, if unchecked pagination displays above the table.'),
    '#states' => array(
      'invisible' => array(
        'input[name="field[settings][pager][enabled]"]' => array(
          'checked' => FALSE,
        ),
      ),
    ),
  );
  $form['modal'] = array(
    '#type' => 'fieldset',
    '#title' => t('Configuration of modal popups'),
    '#collapsed' => FALSE,
    '#collapsible' => FALSE,
  );
  $form['modal']['overlay'] = array(
    '#type' => 'fieldset',
    '#title' => t('Overlay'),
    '#collapsed' => FALSE,
    '#collapsible' => FALSE,
  );
  $form['modal']['overlay']['opacity'] = array(
    '#type' => 'textfield',
    '#title' => t('Opacity'),
    '#default_value' => $settings['modal']['overlay']['opacity'],
    '#maxlength' => 3,
    '#required' => TRUE,
    '#element_validate' => array(
      'editor_note_validate_float_positive_or_zero',
    ),
    '#description' => t('Sets opacity level for overlay where 1 is not transparent at all, 0.6 - 0.4 is nearly 50% see-through, and 0 is completely transparent.'),
  );
  $form['modal']['overlay']['bgcolor'] = array(
    '#type' => 'textfield',
    '#title' => t('Background color'),
    '#default_value' => $settings['modal']['overlay']['bgcolor'],
    '#element_validate' => array(
      'editor_note_validate_hex',
    ),
    '#maxlength' => 6,
    '#required' => TRUE,
    '#description' => t('Sets the background-color of overlay. Supports 6-digits HEX value. Do not include # sign. Example: 000000.'),
  );
  $form['modal']['edit'] = array(
    '#type' => 'fieldset',
    '#title' => t('"Edit" popup'),
    '#collapsed' => FALSE,
    '#collapsible' => FALSE,
  );
  $form['modal']['edit']['width'] = array(
    '#type' => 'textfield',
    '#title' => t('Width'),
    '#default_value' => $settings['modal']['edit']['width'],
    '#element_validate' => array(
      'editor_note_validate_size',
    ),
    '#required' => TRUE,
    '#description' => t('Sets the width of an "Edit" popup. Accepts either numeric value (pixels) or "auto" (the browser calculates the width).'),
  );
  $form['modal']['edit']['height'] = array(
    '#type' => 'textfield',
    '#title' => t('Height'),
    '#default_value' => $settings['modal']['edit']['height'],
    '#element_validate' => array(
      'editor_note_validate_size',
    ),
    '#required' => TRUE,
    '#description' => t('Sets the height of an "Edit" popup. Accepts either numeric value (pixels) or "auto" (the browser calculates the height).'),
  );
  $form['modal']['remove'] = array(
    '#type' => 'fieldset',
    '#title' => t('"Remove" popup'),
    '#collapsed' => FALSE,
    '#collapsible' => FALSE,
  );
  $form['modal']['remove']['width'] = array(
    '#type' => 'textfield',
    '#title' => t('Width'),
    '#default_value' => $settings['modal']['remove']['width'],
    '#element_validate' => array(
      'editor_note_validate_size',
    ),
    '#required' => TRUE,
    '#description' => t('Sets the width of an "Remove" popup. Accepts either numeric value (pixels) or "auto" (the browser calculates the width).'),
  );
  $form['modal']['remove']['height'] = array(
    '#type' => 'textfield',
    '#title' => t('Height'),
    '#default_value' => $settings['modal']['remove']['height'],
    '#element_validate' => array(
      'editor_note_validate_size',
    ),
    '#required' => TRUE,
    '#description' => t('Sets the height of an "Remove" popup. Accepts either numeric value (pixels) or "auto" (the browser calculates the height).'),
  );
  return $form;
}

/**
 * Implements hook_form_FORM_ID_alter() for field_ui_field_edit_form().
 *
 * Alters cardinality field of field settings form.
 */
function editor_note_form_field_ui_field_edit_form_alter(&$form) {
  if ($form['#field']['type'] == 'editor_note') {

    // Makes cardinality field hidden for the field type
    // because the editor is allowed to submit unrestricted amount of notes.
    $form['field']['cardinality'] = array(
      '#type' => 'value',
      '#value' => 1,
    );
  }
}

/**
 * Implements hook_field_widget_info().
 *
 * Registers widget for the field.
 */
function editor_note_field_widget_info() {
  return array(
    'editor_note_field_widget' => array(
      'label' => t('Editor Notes'),
      'field types' => array(
        'editor_note',
      ),
      'settings' => array(),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
        'default value' => FIELD_BEHAVIOR_DEFAULT,
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_form().
 *
 * Creates widget for the field, called for each field item.
 */
function editor_note_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  if ($field['type'] == 'editor_note') {
    $text_processing = !empty($field['settings']['text_processing']) ? $field['settings']['text_processing'] : EDITOR_NOTE_DEFAULT_TEXT_FORMAT;

    // Rich text.
    if ($text_processing == 'filtered_text') {
      $element['#attached']['css'][] = drupal_get_path('module', 'editor_note') . '/css/editor-note-text-format.css';
      $type = 'text_format';
      $format = !empty($instance['default_value'][0]['note']['format']) ? $instance['default_value'][0]['note']['format'] : NULL;
      $default_value = !empty($instance['default_value'][0]['note']['value']) ? $instance['default_value'][0]['note']['value'] : '';
      $maxlength = '';
    }
    else {
      $type = 'textarea';
      $format = NULL;
      $default_value = !empty($instance['default_value'][0]['note']) ? $instance['default_value'][0]['note'] : '';
      $maxlength = $field['settings']['notes_maxlength'] > 0 ? $field['settings']['notes_maxlength'] : '';
    }
    $element['note'] = array(
      '#type' => $type,
      '#prefix' => '<div id="textarea_' . $field['field_name'] . '" class="editor_note_field_wrapper">',
      '#suffix' => '</div>',
      '#title' => check_plain($instance['label']) . ($instance['required'] ? ' ' . theme('form_required_marker') : ''),
      '#default_value' => $default_value,
      '#format' => $format,
      '#description' => $instance['description'],
      '#rows' => $field['settings']['notes_size'],
      '#resizable' => FALSE,
      '#weight' => $field['settings']['display'] ? 1 : 4,
      '#attributes' => array(
        'maxlength' => $maxlength,
        'placeholder' => $field['settings']['notes_placeholder'],
      ),
    );
    if (isset($instance['entity_type']) && isset($form['#entity'])) {
      list($entity_id) = entity_extract_ids($instance['entity_type'], $form['#entity']);
    }
    if (isset($entity_id)) {

      // Load CTools components for modal popups.
      editor_note_load_ctools_modal($field);
      $notes = editor_note_get_notes($instance['entity_type'], $form['#entity'], $field);
      $formatted_notes = editor_note_get_formatted_notes($field, $notes, TRUE);

      // Display 'Add Note' button only if entity has been already created
      // and stored in the database.
      $element['note_add'] = array(
        '#type' => 'submit',
        '#name' => $field['field_name'] . '_add_note',
        '#value' => t('Add note'),
        '#submit' => array(
          'editor_note_add_note_submit',
        ),
        '#validate' => array(
          'editor_note_add_note_validate',
        ),
        '#limit_validation_errors' => array(
          array(
            $field['field_name'],
          ),
        ),
        '#weight' => $field['settings']['display'] ? 2 : 5,
        '#ajax' => array(
          'callback' => 'editor_note_add_note',
          'event' => 'click',
        ),
      );
      $element['message'] = array(
        '#type' => 'container',
        '#attributes' => array(
          'id' => array(
            'status_message_' . $element['#field_name'],
          ),
        ),
        '#value' => '',
        '#weight' => 3,
      );
      $element['formatted_notes'] = array(
        '#markup' => drupal_render($formatted_notes),
        '#weight' => $field['settings']['display'] ? 4 : 1,
      );
      $element['note_entity_id'] = array(
        '#type' => 'value',
        '#value' => $entity_id,
      );
      if (isset($form_state['triggering_element']['#name']) && $form_state['triggering_element']['#name'] == $field['field_name'] . '_add_note') {

        // Fixing Ajax #default_value issue, https://drupal.org/node/1082818.
        $storage = 'input';
        unset($form_state[$storage][$field['field_name']][LANGUAGE_NONE][0]['note']);
      }
    }
  }
  return $element;
}

/**
 * Implements hook_field_validate().
 *
 * Defines messages that will be shown on validation of widget form
 * using hook_field_widget_error().
 */
function editor_note_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
  if ($field['type'] == 'editor_note') {
    foreach ($items as $delta => $item) {
      if ($entity_type && $entity) {

        // Field widget form validation, otherwise field settings form.
        if (empty($item['note']) && $instance['required']) {
          $errors[$field['field_name']][$langcode][$delta][] = array(
            'error' => 'note',
            'message' => t('Field %name is required.', array(
              '%name' => $instance['label'],
            )),
          );
        }
      }
      if (isset($instance['settings']['text_processing']) && $instance['settings']['text_processing'] != EDITOR_NOTE_DEFAULT_TEXT_FORMAT) {
        $text_processing = TRUE;
      }

      // Maxlength check applies for plain text only.
      if (!$text_processing) {
        if (!empty($item['note']) && $field['settings']['notes_maxlength'] > 0) {
          if (drupal_strlen($item['note']) > $field['settings']['notes_maxlength']) {
            $errors[$field['field_name']][$langcode][$delta][] = array(
              'error' => 'notes_maxlength',
              'message' => t('%name: the value cannot not be longer than %max characters.', array(
                '%name' => $instance['label'],
                '%max' => $field['settings']['notes_maxlength'],
              )),
            );
          }
        }
      }

      // Validate first element since there can be only 1 textarea and 1 item
      // for adding notes.
      break;
    }
  }
}

/**
 * Implements hook_field_widget_error().
 *
 * Displays validation errors if present and prevents form submit.
 */
function editor_note_field_widget_error($element, $error) {
  form_error($element, $error['message']);
}

/**
 * Implements hook_field_insert().
 *
 * Executes once on adding new entity to the database.
 */
function editor_note_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
  if ($field['type'] == 'editor_note') {
    foreach ($items as $item) {
      editor_note_save($item['note'], $entity_type, $entity, $field['field_name']);
    }
  }
}

/**
 * Implements hook_field_update().
 *
 * Executes every time entity gets updated.
 */
function editor_note_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
  if ($field['type'] == 'editor_note') {
    foreach ($items as $item) {
      if (isset($item['note'])) {
        editor_note_save($item['note'], $entity_type, $entity, $field['field_name']);
      }
    }
  }
}

/**
 * Implements hook_field_formatter_info().
 *
 * Registers formatter for the field.
 */
function editor_note_field_formatter_info() {
  return array(
    'editor_note_field_formatter' => array(
      'label' => t('Editor Notes table'),
      'field types' => array(
        'editor_note',
      ),
      'settings' => array(
        'notes_display_mode' => 'per_revision',
        'limit' => 10,
        'order' => 'DESC',
        'display' => 1,
        'pager' => array(
          'enabled' => 1,
          'pager_below' => 1,
        ),
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_settings_form().
 *
 * Creates field formatter forms for registered types of formatters.
 */
function editor_note_field_formatter_settings_form($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $element = array();
  if ($display['type'] == 'editor_note_field_formatter') {
    $element['notes_display_mode'] = array(
      '#type' => 'radios',
      '#title' => t('Display mode'),
      '#required' => TRUE,
      '#description' => t('"Display list of notes per entity revision" means separate list of notes for each revision while "Display list of notes per entity" displays combined list of notes for all revisions.'),
      '#default_value' => isset($settings['notes_display_mode']) ? $settings['notes_display_mode'] : 'per_revision',
      '#options' => array(
        'per_revision' => t('Display list of notes per entity revision'),
        'per_entity' => t('Display list of notes per entity'),
      ),
    );
    $element['limit'] = array(
      '#type' => 'textfield',
      '#title' => t('Display a specified number of items.'),
      '#default_value' => $settings['limit'],
      '#required' => TRUE,
      '#description' => t('Display a specified number of items in table. Set 0 for no limit.'),
      '#element_validate' => array(
        'editor_note_validate_integer_positive_or_zero',
      ),
    );
    $element['order'] = array(
      '#type' => 'radios',
      '#title' => t('Order notes'),
      '#options' => array(
        'DESC' => t('display recently updated notes first'),
        'ASC' => t('display recently updated notes last'),
      ),
      '#default_value' => $settings['order'],
      '#description' => t('Set order of notes in the table.'),
    );
    $element['pager'] = array(
      '#type' => 'fieldset',
      '#title' => t('Pagination'),
      '#collapsed' => FALSE,
      '#collapsible' => FALSE,
      '#states' => array(
        'invisible' => array(
          'input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][limit]"]' => array(
            'value' => 0,
          ),
        ),
      ),
    );
    $element['pager']['enabled'] = array(
      '#type' => 'checkbox',
      '#title' => t('Enable pagination'),
      '#default_value' => $settings['pager']['enabled'],
      '#description' => t('Whether to display pagination if number of notes added is greater that can be displayed.'),
    );
    $element['pager']['pager_below'] = array(
      '#type' => 'checkbox',
      '#title' => t('Pagination below notes table'),
      '#default_value' => $settings['pager']['pager_below'],
      '#description' => t('Displays pagination below the notes table, if unchecked pagination displays above the table.'),
      '#states' => array(
        'invisible' => array(
          'input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][pager][enabled]"]' => array(
            'checked' => FALSE,
          ),
        ),
      ),
    );
  }
  return $element;
}

/**
 * Implements hook_field_formatter_settings_summary().
 *
 * Displays summary of enabled settings for the field on Manage Display page.
 * Essential for proper work of hook_field_formatter_settings_form() because
 * it adds ajax-powered button that opens formatter_settings_form.
 *
 * Note that button is present only if this hook returns non empty value.
 *
 * @see field_ui_display_overview_form()
 */
function editor_note_field_formatter_settings_summary($field, $instance, $view_mode) {
  $display = $instance['display'][$view_mode];
  $settings = $display['settings'];
  $summary = array();
  if ($display['type'] == 'editor_note_field_formatter') {
    $display_mode_raw = isset($settings['notes_display_mode']) ? $settings['notes_display_mode'] : 'per_revision';
    $display_mode = $display_mode_raw == 'per_revision' ? t('display list of notes per entity revision') : t('display list of notes per entity');
    $order = $settings['order'] == 'DESC' ? t('display recently updated notes first') : t('display recently updated notes last');
    $summary[] = t('Display mode: @display_mode.', array(
      '@display_mode' => $display_mode,
    ));
    $summary[] = t('Display a specified number of items: @limit.', array(
      '@limit' => $display['settings']['limit'],
    ));
    $summary[] = t('Notes Ordering: !order.', array(
      '!order' => $order,
    ));
    if ($display['settings']['limit'] > 0) {
      $summary[] = t('Enable pagination: !enabled.', array(
        '!enabled' => $settings['pager']['enabled'] ? 'true' : 'false',
      ));
      $summary[] = t('Pagination below notes table: !pager.', array(
        '!pager' => $settings['pager']['pager_below'] ? 'true' : 'false',
      ));
    }
  }
  return !empty($summary) ? implode('<br />', $summary) : '';
}

/**
 * Implements hook_field_load().
 *
 * Defines custom load behavior for the field properties
 * available in entity object.
 */
function editor_note_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
  if ($field['type'] == 'editor_note') {
    foreach ($entities as $id => $entity) {
      $delta = 0;
      $notes = editor_note_get_notes($entity_type, $entity, $field, TRUE);
      foreach ($notes as $note_id) {
        $items[$id][$delta]['editor_note_id'] = $note_id;
        $delta++;
      }
    }
  }
}

/**
 * Implements hook_field_formatter_view().
 *
 * Builds registered formatters for the field, returns renderable array.
 */
function editor_note_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  if ($display['type'] == 'editor_note_field_formatter') {
    $display['field_name'] = $field['field_name'];
    $display['settings']['notes_display_mode'] = isset($display['settings']['notes_display_mode']) ? $display['settings']['notes_display_mode'] : 'per_revision';
    $notes = editor_note_get_notes($entity_type, $entity, $display);
    if (!empty($notes)) {
      $element[][$field['field_name']] = editor_note_get_formatted_notes($display, $notes);
    }
  }
  return $element;
}

/**
 * Saves note.
 *
 * @param string|array $note
 *   The text of the note | note array.
 * @param string $entity_type
 *   The type of the entity.
 * @param object $entity
 *   The entity object.
 * @param string $field_name
 *   The machine field name.
 * @param int|string|null $uid
 *   The unique ID of the author.
 * @param int|string|null $created
 *   The Unix timestamp of the note creation.
 * @param int|string|null $changed
 *   The Unix timestamp of the note update.
 */
function editor_note_save($note, $entity_type, $entity, $field_name, $uid = NULL, $created = NULL, $changed = NULL) {
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
  if (!isset($revision_id)) {
    $revision_id = $entity_id;
  }
  if (!isset($uid)) {
    global $user;
    $uid = $user->uid;
  }
  $field_info = field_info_field($field_name);
  $text_processing = FALSE;
  if (isset($field_info['settings']['text_processing']) && $field_info['settings']['text_processing'] != EDITOR_NOTE_DEFAULT_TEXT_FORMAT) {
    $text_processing = TRUE;
  }
  $editor_note = entity_create('editor_note', array(
    'note' => $text_processing ? $note['value'] : $note,
    'bundle' => $bundle,
    'entity_type' => $entity_type,
    'field_name' => $field_name,
    'entity_id' => $entity_id,
    'revision_id' => $revision_id,
    'uid' => (int) $uid,
    'created' => isset($created) ? $created : REQUEST_TIME,
    'changed' => isset($changed) ? $changed : REQUEST_TIME,
    'text_format' => $text_processing ? $note['format'] : EDITOR_NOTE_DEFAULT_TEXT_FORMAT,
  ));
  entity_save('editor_note', $editor_note);
}

/**
 * Loads single note based on certain conditions.
 *
 * @param int|string $note_id
 *   The unique ID of the note entry.
 * @param array $conditions
 *   An associative array of conditions used by entity_load() (deprecated).
 * @param bool $reset
 *   Whether to reset the internal cache for the requested entity type.
 *
 * @return object|bool
 *   Success: loaded note object.
 *   Fail: boolean indicating that query failed.
 *
 * @see entity_load()
 */
function editor_note_load($note_id, array $conditions = array(), $reset = FALSE) {
  $note_array = entity_load('editor_note', array(
    $note_id,
  ), $conditions, $reset);
  if (!empty($note_array)) {
    return $note_array[$note_id];
  }
  return FALSE;
}

/**
 * Deletes single note.
 *
 * @param int|string $note_id
 *   The unique ID of the note entry.
 */
function editor_note_delete($note_id) {
  entity_delete('editor_note', $note_id);
}

/**
 * Returns array of notes per entity revision.
 *
 * @param string $entity_type
 *   The type of the entity.
 * @param object $entity
 *   The entity object.
 * @param array $field
 *   The field data about an individual field.
 * @param bool $id_only
 *   Determines whether to return an array of note ids instead of
 *   fully loaded notes.
 *
 * @return array
 *   An associative array, or an empty array if there is no result set.
 */
function editor_note_get_notes($entity_type, $entity, array $field, $id_only = FALSE) {
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
  if (!isset($revision_id)) {
    $revision_id = $entity_id;
  }
  $notes_display_mode = isset($field['settings']['notes_display_mode']) ? $field['settings']['notes_display_mode'] : 'per_revision';
  $query = db_select('editor_note', 'en');
  $query
    ->condition('en.entity_type', $entity_type, '=')
    ->condition('en.entity_id', $entity_id, '=')
    ->condition('en.bundle', $bundle, '=')
    ->condition('en.field_name', $field['field_name'], '=')
    ->orderBy('en.changed', $field['settings']['order']);
  if ($notes_display_mode == 'per_revision') {
    $query
      ->condition('en.revision_id', $revision_id, '=');
  }
  if ($id_only) {
    $ids = $query
      ->fields('en', array(
      'id',
    ))
      ->execute()
      ->fetchAllKeyed(0, 0);
    return array_values($ids);
  }
  $columns = array(
    'id',
    'note',
    'entity_type',
    'bundle',
    'field_name',
    'entity_id',
    'revision_id',
    'uid',
    'created',
    'changed',
    'text_format',
  );
  $query
    ->fields('en', $columns);
  if ($field['settings']['limit'] > 0) {
    if ($field['settings']['pager']['enabled']) {
      $query = $query
        ->extend('PagerDefault');
      $query
        ->limit($field['settings']['limit']);
    }
    else {
      $query
        ->range(0, $field['settings']['limit']);
    }
  }
  return $query
    ->execute()
    ->fetchAllAssoc('id');
}

/**
 * Returns formatted notes table.
 *
 * @param array $field
 *   The field data about an individual field.
 * @param array $notes
 *   Array of notes data returned by editor_note_get_notes().
 * @param bool $widget
 *   Determines whether to use function in widget along with controls or
 *   display it in formatter as just a table without controls.
 * @param string|null $edit_path
 *   Path of the edit form where field is used. Fixes pager on ajax refresh.
 *
 * @return array
 *   Returns formatted notes ready for rendering.
 *
 * @see editor_note_get_notes()
 */
function editor_note_get_formatted_notes(array $field, array $notes, $widget = FALSE, $edit_path = NULL) {
  $formatted_notes = array(
    '#prefix' => '<div id="formatted_notes_' . $field['field_name'] . '">',
    '#suffix' => '</div>',
  );
  if (!empty($notes)) {
    $rows = array();
    $counter = 0;
    $header = array(
      array(
        'data' => t('Notes'),
        'class' => array(
          'field-label',
        ),
      ),
      array(
        'data' => t('Updated by'),
        'class' => array(
          'field-author',
        ),
      ),
      array(
        'data' => t('Changed'),
        'class' => array(
          'field-changed',
        ),
      ),
      array(
        'data' => t('Created'),
        'class' => array(
          'field-created',
        ),
      ),
    );
    if ($widget) {
      $header[] = array(
        'data' => t('Actions'),
        'class' => array(
          'field-operations',
        ),
      );
    }
    $field_info = field_info_field($field['field_name']);
    $text_processing = isset($field_info['settings']['text_processing']) ? $field_info['settings']['text_processing'] : EDITOR_NOTE_DEFAULT_TEXT_FORMAT;
    foreach ($notes as $note_id => $item) {
      $author_name = format_username(user_load($item->uid));
      $rows[$counter] = array(
        'data' => array(
          'note' => array(
            /*
             * Retain line breaks if 'plain_text' processing is selected in field settings.
             * Otherwise just filter potentially dangerous content.
             */
            'data' => $text_processing == EDITOR_NOTE_DEFAULT_TEXT_FORMAT ? nl2br(check_plain($item->note)) : check_markup($item->note, $item->text_format),
            'class' => array(
              'note',
            ),
          ),
          'author' => array(
            'uid' => $item->uid,
            'data' => user_access('access user profiles') ? l($author_name, 'user/' . $item->uid) : $author_name,
            'class' => array(
              'author',
            ),
          ),
          'changed' => array(
            'data' => format_date($item->changed, 'short'),
            'class' => array(
              'changed',
            ),
          ),
          'created' => array(
            'data' => format_date($item->created, 'short'),
            'class' => array(
              'created',
            ),
          ),
        ),
        'class' => array(
          drupal_html_class('note-' . $note_id),
        ),
      );
      if ($widget) {
        $operations = !editor_note_access_crud_operations($field['field_name'], $note_id) ? '' : theme('item_list', array(
          'items' => array(
            ctools_modal_text_button(t('edit'), 'editor_note/edit/nojs/' . $field['field_name'] . '/' . $note_id, t('Edit the note'), drupal_html_class('ctools-modal-' . $field['field_name'] . '-edit')),
            ctools_modal_text_button(t('remove'), 'editor_note/remove/nojs/' . $field['field_name'] . '/' . $note_id, t('Remove the note'), drupal_html_class('ctools-modal-' . $field['field_name'] . '-remove')),
          ),
        ));
        $rows[$counter]['data']['operations'] = array(
          'data' => $operations,
          'class' => array(
            'operations',
          ),
        );
      }
      $counter++;
    }
    $notes_table = array(
      '#theme' => 'table',
      '#header' => $header,
      '#rows' => $rows,
      '#attributes' => array(
        'class' => array(
          'field-notes-table',
        ),
      ),
    );
    if ($field['settings']['pager']['enabled']) {

      // An optional integer to distinguish between multiple pagers on one page
      // in case if 2 fields are present at the same time.
      static $page_element = 0;

      // Fixes pager on ajax refresh.
      // Otherwise pager links point on /system/ajax after ajax refresh.
      // @see https://www.drupal.org/node/1181370#comment-6088864
      // for more details.
      // @see theme_pager_link()
      if ($edit_path) {
        $_GET['q'] = $edit_path;
      }
      if ($field['settings']['pager']['pager_below']) {
        $formatted_notes['notes_table'] = $notes_table;
        $formatted_notes['notes_table_pager'] = array(
          '#theme' => 'pager',
          '#element' => $page_element,
        );
      }
      else {
        $formatted_notes['notes_table_pager'] = array(
          '#theme' => 'pager',
          '#element' => $page_element,
        );
        $formatted_notes['notes_table'] = $notes_table;
      }
      if (module_exists('field_group')) {

        // Remember which tab was active after page reload
        // when navigating between pager links.
        $settings = array(
          'editorNoteContainer' => drupal_html_class('edit-' . $field['field_name']),
        );
        $formatted_notes['notes_table']['#attached']['js'][] = array(
          'data' => $settings,
          'type' => 'setting',
        );
        $formatted_notes['notes_table']['#attached']['js'][] = drupal_get_path('module', 'editor_note') . '/js/editor_note.js';
      }
      $page_element++;
    }
    else {
      $formatted_notes['notes_table'] = $notes_table;
    }
  }

  // Hook is to allow other modules to alter the formatted notes
  // before they are rendered.
  drupal_alter('editor_note_format_notes', $formatted_notes);
  return $formatted_notes;
}

/**
 * Defines access callback for CRUD operations.
 *
 * @param int|string $note_id
 *   The unique ID of the note entry.
 *
 * @return bool
 *   Boolean indicating whether the user may perform operations on notes or not.
 */
function editor_note_access_crud_operations($field_name, $note_id) {
  $field = field_info_field($field_name);
  if (!$field) {
    return FALSE;
  }
  global $user;
  $create_only_permission = isset($field['settings']['notes_permissions']) && $field['settings']['notes_permissions'] == 'create_only';
  if ($create_only_permission && $user->uid != 1) {
    return FALSE;
  }
  $note_uid = db_query('SELECT en.uid FROM {editor_note} en WHERE id = :id', array(
    ':id' => $note_id,
  ))
    ->fetchField();
  return user_access('administer any editor note') || $user->uid == $note_uid;
}

/**
 * Validates form element that accepts positive integer or 0.
 */
function editor_note_validate_integer_positive_or_zero($element, &$form_state) {

  // Checks for positive integer (or zero) value.
  preg_match('/^[0-9]\\d*$/', trim($element['#value']), $matches);
  if (empty($matches)) {
    form_error($element, t('%name must be a positive integer or 0.', array(
      '%name' => $element['#title'],
    )));
  }
}

/**
 * Validates form element that accepts float value and must be >= 0 or <= 1.
 */
function editor_note_validate_float_positive_or_zero($element, &$form_state) {
  $value = trim($element['#value']);
  if (!is_numeric($value) || $value < 0 || $value > 1) {
    form_error($element, t('%name must be between 0 and 1.', array(
      '%name' => $element['#title'],
    )));
  }
}

/**
 * Validates form element that accepts HEX value.
 */
function editor_note_validate_hex($element, &$form_state) {
  preg_match('/^[0-9A-Fa-f]{6}$/', trim($element['#value']), $matches);
  if (empty($matches)) {
    form_error($element, t('%name should contain combination of 6 [0-9A-Fa-f] symbols.', array(
      '%name' => $element['#title'],
    )));
  }
}

/**
 * Validates form element that accepts positive integer value (px) or 'auto'.
 */
function editor_note_validate_size($element, &$form_state) {
  $value = $element['#value'];
  if (is_string($value) && $value !== 'auto' && ($value !== '' && (!is_numeric($value) || intval($value) != $value || $value <= 0))) {
    $error = t('%name accepts either positive integer value (pixels) or "auto" (the browser calculates the height).', array(
      '%name' => $element['#title'],
    ));
    form_error($element, $error);
  }
}

/**
 * Validates value of 'Create a note' textarea during adding a note via ajax.
 */
function editor_note_add_note_validate(&$form, &$form_state) {
  $field_name = str_replace('_add_note', '', $form_state['triggering_element']['#name']);
  $field_info = field_info_instance($form['#entity_type'], $field_name, $form['#bundle']);
  $field = field_info_field($field_name);
  $note = $form_state['values'][$field_name][LANGUAGE_NONE][0]['note'];
  if (empty($note)) {
    form_set_error($field_name, t('Field %field_name is required.', array(
      '%field_name' => $field_info['label'],
    )));
  }
  if (!empty($note) && $field['settings']['notes_maxlength'] > 0) {
    if (drupal_strlen($note) > $field['settings']['notes_maxlength']) {
      form_set_error($field_name, t('%name: the value cannot not be longer than %max characters.', array(
        '%name' => $field_info['label'],
        '%max' => $field['settings']['notes_maxlength'],
      )));
    }
  }
}

/**
 * Ajax callback for 'Add note' button in 'editor_note_field_widget_form'.
 */
function editor_note_add_note(&$form, &$form_state) {
  $ajax_commands = array();
  $entity_type = $form['#entity_type'];
  $entity = $form['#entity'];
  $field_name = str_replace('_add_note', '', $form_state['triggering_element']['#name']);
  $note = $form_state['values'][$field_name][LANGUAGE_NONE][0]['note'];
  $entity_id = $form_state['values'][$field_name][LANGUAGE_NONE][0]['note_entity_id'];
  $edit_path = implode('/', array(
    $entity_type,
    $entity_id,
    'edit',
  ));
  $errors = form_get_errors();
  if (!empty($errors) && isset($errors[$field_name])) {

    // Displays validation message.
    $message = theme('editor_note_message', array(
      'field_name' => $field_name,
      'message_text' => $errors[$field_name],
      'message_type' => 'error',
    ));
  }
  else {

    // Adds note entity to the database.
    editor_note_save($note, $entity_type, $entity, $field_name);

    // Displays status message.
    $message = theme('editor_note_message', array(
      'field_name' => $field_name,
      'message_text' => t('Note has been added and saved.'),
      'message_type' => 'status',
    ));

    // Updates notes table and pager.
    $field = field_info_field($field_name);
    $notes = editor_note_get_notes($entity_type, $entity, $field);
    $formatted_notes = editor_note_get_formatted_notes($field, $notes, TRUE, $edit_path);
    $ajax_commands[] = ajax_command_replace('#formatted_notes_' . $field_name, drupal_render($formatted_notes));

    // Returns blank textarea for adding notes.
    $form[$field_name][LANGUAGE_NONE][0]['note']['#default_value'] = '';
  }
  $ajax_commands[] = ajax_command_replace('#status_message_' . $field_name, $message);
  $ajax_commands[] = ajax_command_replace('#textarea_' . $field_name, drupal_render($form[$field_name][LANGUAGE_NONE][0]['note']));
  return array(
    '#type' => 'ajax',
    '#commands' => $ajax_commands,
  );
}

/**
 * Submit callback for 'editor_note_field_widget_form'.
 */
function editor_note_add_note_submit(&$form, &$form_state) {
  $form_state['rebuild'] = TRUE;
}

/**
 * Enables support of CTools module for Ajax operations.
 *
 * @param array $field
 *   The field data about an individual field.
 */
function editor_note_load_ctools_modal(array $field) {

  // Includes the CTools tools that we need.
  ctools_include('ajax');
  ctools_include('modal');

  // Adds CTools' javascript to the page.
  ctools_modal_add_js();
  $modal_remove_width = $field['settings']['modal']['remove']['width'];
  $modal_remove_height = $field['settings']['modal']['remove']['height'];
  $modal_edit_width = $field['settings']['modal']['edit']['width'];
  $modal_edit_height = $field['settings']['modal']['edit']['height'];

  // Creates javascript settings to customize modal.
  $modal_styles = array(
    drupal_html_class($field['field_name'] . '-remove') => array(
      'modalSize' => array(
        'type' => 'fixed',
        'width' => $modal_remove_width == 'auto' ? $modal_remove_width : (int) $modal_remove_width,
        'height' => $modal_remove_height == 'auto' ? $modal_remove_height : (int) $modal_remove_height,
      ),
      'modalOptions' => array(
        'opacity' => $field['settings']['modal']['overlay']['opacity'],
        'background-color' => '#' . $field['settings']['modal']['overlay']['bgcolor'],
      ),
      'animation' => 'show',
    ),
    drupal_html_class($field['field_name'] . '-edit') => array(
      'modalSize' => array(
        'type' => 'fixed',
        'width' => $modal_edit_width == 'auto' ? $modal_edit_width : (int) $modal_edit_width,
        'height' => $modal_edit_height == 'auto' ? $modal_edit_height : (int) $modal_edit_height,
      ),
      'modalOptions' => array(
        'opacity' => $field['settings']['modal']['overlay']['opacity'],
        'background-color' => '#' . $field['settings']['modal']['overlay']['bgcolor'],
      ),
      'animation' => 'show',
    ),
  );

  // Passes CTools modal settings to js.
  drupal_add_js($modal_styles, 'setting');

  // Adds custom css to style popups.
  ctools_add_css('editor-note-ctools-style', 'editor_note');
}

/**
 * Returns formatted status message for Ajax-triggered actions.
 */
function theme_editor_note_message($variables) {
  $field_name = $variables['field_name'];
  $message_text = $variables['message_text'];
  $message_type = $variables['message_type'];
  if (!empty($message_text) && !empty($message_type)) {
    return '<div id="status_message_' . $field_name . '">
    <div class="messages ' . $message_type . '">' . $message_text . '</div></div>';
  }
  else {
    return '<div id="status_message_' . $field_name . '"></div>';
  }
}

Functions

Namesort descending Description
editor_note_access_crud_operations Defines access callback for CRUD operations.
editor_note_add_note Ajax callback for 'Add note' button in 'editor_note_field_widget_form'.
editor_note_add_note_submit Submit callback for 'editor_note_field_widget_form'.
editor_note_add_note_validate Validates value of 'Create a note' textarea during adding a note via ajax.
editor_note_delete Deletes single note.
editor_note_entity_delete Implements hook_entity_delete().
editor_note_entity_info Implements hook_entity_info().
editor_note_entity_property_info Implements hook_entity_property_info().
editor_note_field_delete_instance Implements hook_field_delete_instance().
editor_note_field_formatter_info Implements hook_field_formatter_info().
editor_note_field_formatter_settings_form Implements hook_field_formatter_settings_form().
editor_note_field_formatter_settings_summary Implements hook_field_formatter_settings_summary().
editor_note_field_formatter_view Implements hook_field_formatter_view().
editor_note_field_info Implements hook_field_info().
editor_note_field_insert Implements hook_field_insert().
editor_note_field_is_empty Implements hook_field_is_empty().
editor_note_field_load Implements hook_field_load().
editor_note_field_settings_form Implements hook_field_settings_form().
editor_note_field_update Implements hook_field_update().
editor_note_field_validate Implements hook_field_validate().
editor_note_field_widget_error Implements hook_field_widget_error().
editor_note_field_widget_form Implements hook_field_widget_form().
editor_note_field_widget_info Implements hook_field_widget_info().
editor_note_form_field_ui_field_edit_form_alter Implements hook_form_FORM_ID_alter() for field_ui_field_edit_form().
editor_note_get_formatted_notes Returns formatted notes table.
editor_note_get_notes Returns array of notes per entity revision.
editor_note_help Implements hook_help().
editor_note_load Loads single note based on certain conditions.
editor_note_load_ctools_modal Enables support of CTools module for Ajax operations.
editor_note_menu Implements hook_menu().
editor_note_node_revision_delete Implements hook_node_revision_delete().
editor_note_permission Implements hook_permission().
editor_note_save Saves note.
editor_note_theme Implements hook_theme().
editor_note_validate_float_positive_or_zero Validates form element that accepts float value and must be >= 0 or <= 1.
editor_note_validate_hex Validates form element that accepts HEX value.
editor_note_validate_integer_positive_or_zero Validates form element that accepts positive integer or 0.
editor_note_validate_size Validates form element that accepts positive integer value (px) or 'auto'.
editor_note_views_data_alter Implements hook_views_data_alter().
theme_editor_note_message Returns formatted status message for Ajax-triggered actions.

Constants

Namesort descending Description
EDITOR_NOTE_DEFAULT_TEXT_FORMAT @file Main functionality for Editor Notes module.