You are here

jeditable.module in jEditable inline content editing 6

Same filename and directory in other branches
  1. 6.2 jeditable.module
  2. 7 jeditable.module

File

jeditable.module
View source
<?php

/**
 * @file jeditable.module
 */

/************************************
* DEFINES
*************************************/
define('JEDITABLE_DIR', drupal_get_path('module', 'jeditable'));
define('JEDITABLE_DIR_PLUGIN', function_exists('libraries_get_path') ? libraries_get_path('jeditable') : JEDITABLE_DIR);

/************************************
* FUNCTIONS
*************************************/

/**
 * Implementation of hook_menu()
 */
function jeditable_menu() {
  $items['jeditable/ajax/save'] = array(
    'title' => 'Save field',
    'page callback' => '_jeditable_ajax_save',
    'access arguments' => array(
      'use jeditable',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['jeditable/ajax/load'] = array(
    'title' => 'Load field',
    'page callback' => '_jeditable_ajax_load',
    'page arguments' => array(
      3,
      4,
      5,
    ),
    'access arguments' => array(
      'use jeditable',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/settings/jeditable'] = array(
    'title' => 'jEditable',
    'description' => 'Configure the jEditable module.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'jeditable_admin_settings',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}
function jeditable_admin_settings() {
  $form['jeditable_create_new_revisions'] = array(
    '#type' => 'checkbox',
    '#title' => t('Create Node Revisions'),
    '#default_value' => variable_get('jeditable_create_new_revisions', 0),
    '#description' => t('If enabled, each time a field is changed a new node revision will be generated. This will generate a very full revision table if jeditable is used extensively, so use with caution'),
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_perm()
 */
function jeditable_perm() {
  return array(
    'use jeditable',
  );
}

/**
 * Implementation of hook_init().
 */
function jeditable_init() {
  if (user_access('use jeditable')) {
    drupal_add_js(JEDITABLE_DIR_PLUGIN . '/jquery.jeditable.mini.js', 'module');
    drupal_add_js(JEDITABLE_DIR . '/drupal_jeditable.js', 'module');
    drupal_add_css(JEDITABLE_DIR . '/jeditable.css', 'theme');
  }
}

/**
 * Implementation of hook_field_formatter_info(),.
 */
function jeditable_field_formatter_info() {
  return array(
    'jeditable_textfield' => array(
      'label' => t('jEditable Textfield'),
      'field types' => array(
        'text',
        'number_integer',
        'number_decimal',
        'number_float',
      ),
      'multiple values' => CONTENT_HANDLE_MODULE,
    ),
    'jeditable_textarea' => array(
      'label' => t('jEditable Textarea'),
      'field types' => array(
        'text',
      ),
      'multiple values' => CONTENT_HANDLE_MODULE,
    ),
    'jeditable_nodereference' => array(
      'label' => t('jEditable Nodereference'),
      'field types' => array(
        'nodereference',
      ),
      'multiple values' => CONTENT_HANDLE_MODULE,
    ),
    'jeditable_datetime' => array(
      'label' => t('jEditable Datetime picker'),
      'field types' => array(
        'datetime',
      ),
      'multiple values' => CONTENT_HANDLE_MODULE,
    ),
  );
}

/**
 * Implementation of hook_theme().
 */
function jeditable_theme() {
  return array(
    'jeditable_formatter_jeditable_textfield' => array(
      'arguments' => array(
        'element' => NULL,
      ),
    ),
    'jeditable_formatter_jeditable_textarea' => array(
      'arguments' => array(
        'element' => NULL,
      ),
    ),
    'jeditable_formatter_jeditable_datetime' => array(
      'arguments' => array(
        'element' => NULL,
      ),
    ),
    'jeditable_formatter_jeditable_nodereference' => array(
      'arguments' => array(
        'element' => NULL,
      ),
    ),
    'jeditable_workflow' => array(
      'arguments' => array(
        'node' => NULL,
      ),
    ),
  );
}

/**
 * Theme a CCK text field as a jeditable textfield.
 *
 * @ingroup themeable
 */
function theme_jeditable_formatter_jeditable_textfield($element) {
  $id = $element['#node']->nid;
  $field = $element['#field_name'];
  return '<span id="cck-' . $id . '-' . $field . '" class="jeditable-textfield">' . $element[0]['#item']['value'] . '</span>';
}

/**
 * Theme a CCK text field as a jeditable textarea.
 *
 * @ingroup themeable
 */
function theme_jeditable_formatter_jeditable_textarea($element) {
  $id = $element['#node']->nid;
  $field = $element['#field_name'];
  return '<span id="cck-' . $id . '-' . $field . '" class="jeditable-textarea">' . $element[0]['#item']['value'] . '</span>';
}

/**
 * Theme a CCK text field as a jeditable textarea.
 *
 * @ingroup themeable
 */
function theme_jeditable_formatter_jeditable_nodereference($element) {
  $id = $element['#node']->nid;
  $field = $element['#field_name'];
  $node = node_load($element[0]['#item']['nid']);
  return '<span id="cck-' . $id . '-' . $field . '" class="jeditable-select">' . $node->title . '</span>';
}

/**
 * Theme a CCK text field as a jeditable textfield.
 *
 * @ingroup themeable
 */
function theme_jeditable_formatter_jeditable_datetime($element) {
  $id = $element['#node']->nid;
  $field = $element['#field_name'];
  return '<span id="cck-' . $id . '-' . $field . '" class="jeditable-textfield edit-datetime">' . $element[0]['#item']['value'] . '</span>';
}

/**
 * Theme a workflow state name as a jeditable select list.
 *
 * @param object $node
 *   The node object to be displayed
 * 
 * @ingroup themeable
 */
function theme_jeditable_workflow($node) {
  $id = $node->nid;

  // in this case we can use field to store the current workflow id
  $field = $node->_workflow ? $node->_workflow : $node->workflow;

  // named differently depending on how far the node has loaded
  $state = workflow_get_state_name($field);
  return '<span id="workflow-' . $id . '-' . $field . '" class="jeditable-select">' . $state . '</span>';
}

/**
 * Helper function to save a value using the jeditable callback
 */
function _jeditable_ajax_save() {

  // Retrieve the values needed from the post to this page
  $array = explode('-', $_POST['id']);
  list($type, $id, $field_name) = $array;
  $value = check_plain($_POST['value']);
  switch ($type) {
    case 'node':
      $node = node_load($id);
      if (!node_access('update', $node)) {

        // check to see that current user has update permissions on the node
        $value = 'access denied';

        // this is the value that will be returned, but no updates made
      }
      else {
        $node->{$field_name} = $value;
        $node->revision = variable_get('jeditable_create_new_revisions', false);
        node_save($node);
      }
      break;
    case 'cck':
      $node = node_load($id);

      // Check to see that current user has update permissions on the node
      if (!node_access('update', $node)) {

        // This is the value that will be returned, but no updates made
        $value = 'access denied';
      }
      else {
        $field = content_fields($field_name, $node->type);
        switch ($field['type']) {
          case 'nodereference':
            $value = _jeditable_save_nodereference_field($node, $field, $value);
            break;
          case 'userreference':
            $value = _jeditable_save_userreference_field($node, $field, $value);
            break;
          case 'datetime':
            $value = _jeditable_save_date_field($node, $field, $value);
            break;
          default:
            $value = _jeditable_save_other_field($node, $field, $value);
            break;
        }
        $node->revision = variable_get('jeditable_create_new_revisions', false);
      }
      break;
    case 'user':

      /** should be implemented if user reference field is implemented **/
      $user = user_load(array(
        'uid' => $id,
      ));
      $user->{$field_name} = $value;
      user_save($user);
      break;
    case 'workflow':
      $node = node_load($id);
      $value = _jeditable_workflow_save($node, $value);
      break;
  }
  print $value;
  exit;
}

/**
 * Helper function to save nodereference field
 */
function _jeditable_save_nodereference_field($node, $field, $value) {
  module_load_include('inc', 'node', 'node.pages');
  $field_name = $field['field_name'];
  $form_state = array();
  $form_state['values'][$field_name]['nid']['nid'] = $value;
  $form_state['values']['op'] = t('Save');
  $form_id = $node->type . '_node_form';
  drupal_execute($form_id, &$form_state, (object) $node);
  drupal_get_messages('status');

  // Discard status messages
  // @TODO: Do some Ajax with the warning and error messages.

  //$messages = drupal_get_messages();

  // Reload the node to get the value that was saved, if any. Avoid the cache.
  $node = node_load(array(
    "nid" => $node->nid,
  ));
  if (isset($node->{$field_name})) {
    $value = $node->{$field_name}[0]['nid'];
  }
  else {
    $value = NULL;
  }
  $referenced_node = node_load($value);
  $value = $referenced_node->title;

  // @TODO: Should content_format be called here?
  return $value;
}

/**
 * Helper function to save userreference field.
 *
 * @param $node
 *   The node to act on.
 * @param $field
 *   The user reference field to act on.
 * @param $value
 *   The UID of the selected user.
 *
 * @return
 *   The value that was actually saved in the field.
 */
function _jeditable_save_userreference_field($node, $field, $value) {
  module_load_include('inc', 'node', 'node.pages');
  $field_name = $field['field_name'];
  $form_state = array();
  $form_state['values'][$field_name]['uid']['uid'] = $value;
  $form_state['values']['op'] = t('Save');
  $form_id = $node->type . '_node_form';
  drupal_execute($form_id, &$form_state, (object) $node);
  drupal_get_messages('status');

  // Discard status messages
  // @todo: Do some Ajax with the warning and error messages.

  //$messages = drupal_get_messages();

  // Reload the node to get the value that was saved, if any. Avoid the cache.
  $node = node_load(array(
    "nid" => $node->nid,
  ));
  if (isset($node->{$field_name})) {
    $value = $node->{$field_name}[0]['uid'];
  }
  else {
    $value = NULL;
  }
  $referenced_user = user_load(array(
    'uid' => $value,
  ));
  $value = $referenced_user->name;

  // @todo: Should content_format be called here?
  return $value;
}

/**
 * Helper function to save date field
 */
function _jeditable_save_date_field($node, $field, $value) {
  module_load_include('inc', 'node', 'node.pages');
  $field_name = $field['field_name'];
  $form_state = array();
  $form_state['values']['op'] = t('Save');
  switch ($field['widget']['type']) {
    case 'date_select':
      $date = date_parse($value);
      $form_state['values'][$field_name][0]['value']['year'] = $date['year'];
      $form_state['values'][$field_name][0]['value']['month'] = $date['month'];
      $form_state['values'][$field_name][0]['value']['day'] = $date['day'];
      $form_state['values'][$field_name][0]['value']['hour'] = $date['hour'];
      $form_state['values'][$field_name][0]['value']['minute'] = $date['minute'];
      break;
    case 'date_popup':
    case 'date_text':
      $form_state['values'][$field_name][0]['value']['date'] = $value;
      break;
  }
  $form_id = $node->type . '_node_form';
  drupal_execute($form_id, &$form_state, (object) $node);
  drupal_get_messages('status');

  // Discard status messages
  // @TODO: Do some Ajax with the warning and error messages.

  //$messages = drupal_get_messages();

  // Reload the node to get the value that was saved, if any. Avoid the cache.
  $node = node_load(array(
    "nid" => $node->nid,
  ));
  if (isset($node->{$field_name})) {
    $value = $node->{$field_name}[0]['value'];
    $value = content_format($field_name, array(
      'value' => $value,
    ));
  }
  else {
    $value = NULL;
  }

  // Any HTML tags will already be in place outside the editor
  $value = strip_tags($value);
  return $value;
}

/**
 * Helper function to save other fields
 */
function _jeditable_save_other_field($node, $field, $value) {
  module_load_include('inc', 'node', 'node.pages');
  $field_name = $field['field_name'];
  switch ($field['widget']['type']) {
    case 'optionwidgets_buttons':
    case 'optionwidgets_select':
      $defaults = array_values(optionwidgets_options($field));
      $value = $defaults[$value];
      break;
  }
  $form_state = array();
  $form_state['values'][$field_name][0]['value'] = $value;
  $form_state['values']['op'] = t('Save');
  $form_id = $node->type . '_node_form';
  drupal_execute($form_id, &$form_state, (object) $node);
  drupal_get_messages('status');

  // Discard status messages
  // @TODO: Do some Ajax with the warning and error messages.

  //$messages = drupal_get_messages();

  // Reload the node to get the value that was saved, if any. Avoid the cache.
  $node = node_load(array(
    "nid" => $node->nid,
  ));
  if (isset($node->{$field_name})) {
    $value = $node->{$field_name}[0]['value'];
    $value = content_format($field_name, array(
      'value' => $value,
    ));
  }
  else {
    $value = NULL;
  }

  // Any HTML tags will already be in place outside the editor
  $value = strip_tags($value);
  return $value;
}

/**
 * Helper function to load a list of select values
 */
function _jeditable_ajax_load() {

  // Retrieve the values needed from the post to this page
  $array = explode('-', $_GET['id']);
  list($type, $id, $field_name) = $array;
  switch ($type) {
    case 'node':

      /** Not Implemented yet. This is a test case scenario for editing things such as a Node title **/
      $node = node_load($id);
      $value = $node->{$field};
      $value = 'Y';
      $defaults = array(
        'E' => 'Letter E',
        'M' => 'Letter M',
        'Y' => 'Letter Y',
      );
      $defaults['selected'] = $value;
      $defaults = json_encode($defaults);
      break;
    case 'cck':
      $node = node_load($id);
      $field = content_fields($field_name, $node->type);
      switch ($field['type']) {
        case 'nodereference':
          $defaults = _jeditable_get_node_reference_field_values($field);
          $defaults['selected'] = $node->{$field_name}[0]['nid'];
          $defaults = json_encode($defaults);
          break;
        case 'userreference':
          $defaults = _jeditable_get_user_reference_field_values($field);
          $defaults['selected'] = $node->{$field_name}[0]['uid'];
          $defaults = json_encode($defaults);
          break;
        case 'datetime':
          $date = new DateTime($node->{$field_name}[0]['value']);
          $date_format = date_limit_format(date_input_format(NULL, $field), $field['granularity']);
          $defaults = date_format_date($date, 'custom', $date_format);
          break;
        case 'number_decimal':
        case 'number_integer':
        case 'text':
          switch ($field['widget']['type']) {
            case 'optionwidgets_buttons':
            case 'optionwidgets_select':
              $defaults = array_values(optionwidgets_options($field));
              $defaults['selected'] = $node->{$field_name}[0]['value'];
              $defaults = json_encode($defaults);
              break;
            default:
              $defaults = $node->{$field_name}[0]['value'];
              break;
          }
          break;
        default:
          $defaults = $node->{$field_name}[0]['value'];
          break;
      }
      break;
    case 'workflow':

      /** Load the workflow states available to the current user **/
      $node = node_load($id);
      $defaults = json_encode(_jeditable_workflow_load($node, $field_name));
  }
  print $defaults;
  exit;
}

/**
 * Get potential node references for a field.
 *
 * @param $field_name
 *   The name of the field.
 *
 * @return
 *   An associative array of values suitable for a form select list.
 */
function _jeditable_get_node_reference_field_values($field) {
  $values = _nodereference_potential_references($field);
  $defaults = array();
  foreach ($values as $key => $value) {
    $defaults[$key] = $value['rendered'];
  }
  return $defaults;
}

/**
 * Get potential user references for a field.
 *
 * @param $field
 *   The field of interest.
 *
 * @return
 *   An associative array of values suitable for a form select list.
 */
function _jeditable_get_user_reference_field_values($field) {
  $values = _userreference_potential_references($field);
  $defaults = array();
  foreach ($values as $key => $value) {
    $defaults[$key] = $value['rendered'];
  }
  return $defaults;
}

/**
 * Workflow module integration
 *
 * Workflow API functions needed:
 * workflow_execute_transition($node, $sid, $comment = NULL, $force = FALSE); // transition a node
 * workflow_get_state_name($sid); // get a state name from a state id
 * workflow_field_choices($node); // get the workflow selections available to the current user
 * workflow_node_current_state($node); // get the current state of a node
 */

/**
 * Load the defaults array for a workflow select
 *
 * @param object $node
 *   Node object to get workflow states for.
 * @param int $sid
 *   The state id of the current state.
 * @return array
 *   An array of sid => name, including selected for current selection.
 */
function _jeditable_workflow_load($node, $sid) {
  $defaults = workflow_field_choices($node);

  // set selected value
  $defaults['selected'] = $sid;
  return $defaults;
}

/**
 * Set the workflow state of the node
 *
 * @param object $node
 *   Node to be changed.
 * @return string
 *   the status name after state change.
 */
function _jeditable_workflow_save($node, $sid) {
  if ($sid == $node->_workflow) {

    // this means there's nothing to change, so we just return the title
    return workflow_get_state_name($sid);
  }
  else {

    // here's where we do the actual transition. It will fail if user does not have appropriate permissions.
    $new_sid = workflow_execute_transition($node, $sid, 'set using jeditable at ' . referer_uri());
  }
  if (empty($new_sid)) {

    // in this case, the transition failed, so we'll return "access denied"
    return "access denied";
  }

  // finally, this is the intended outcome and we can return the changed state's name
  return workflow_get_state_name($new_sid);
}

/**
 * Implements hook_views_api
 */
function jeditable_views_api() {
  return array(
    'api' => 2,
    'path' => JEDITABLE_DIR . '/views',
  );
}

Functions

Namesort descending Description
jeditable_admin_settings
jeditable_field_formatter_info Implementation of hook_field_formatter_info(),.
jeditable_init Implementation of hook_init().
jeditable_menu Implementation of hook_menu()
jeditable_perm Implementation of hook_perm()
jeditable_theme Implementation of hook_theme().
jeditable_views_api Implements hook_views_api
theme_jeditable_formatter_jeditable_datetime Theme a CCK text field as a jeditable textfield.
theme_jeditable_formatter_jeditable_nodereference Theme a CCK text field as a jeditable textarea.
theme_jeditable_formatter_jeditable_textarea Theme a CCK text field as a jeditable textarea.
theme_jeditable_formatter_jeditable_textfield Theme a CCK text field as a jeditable textfield.
theme_jeditable_workflow Theme a workflow state name as a jeditable select list.
_jeditable_ajax_load Helper function to load a list of select values
_jeditable_ajax_save Helper function to save a value using the jeditable callback
_jeditable_get_node_reference_field_values Get potential node references for a field.
_jeditable_get_user_reference_field_values Get potential user references for a field.
_jeditable_save_date_field Helper function to save date field
_jeditable_save_nodereference_field Helper function to save nodereference field
_jeditable_save_other_field Helper function to save other fields
_jeditable_save_userreference_field Helper function to save userreference field.
_jeditable_workflow_load Load the defaults array for a workflow select
_jeditable_workflow_save Set the workflow state of the node

Constants