t('Ajax Forms Settings'), 'description' => t('Controls which forms should use AJAX submissions.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('zzzz_ajax_admin'), 'access arguments' => array('access administration pages'), 'type' => MENU_NORMAL_ITEM, ); return $items; } /** * Get content types * * @return Assoc */ function zzzz_ajax_types() { return array_merge( zzzz_ajax_types_node(), zzzz_ajax_types_webform(), //zzzz_ajax_types_module() zzzz_ajax_types_other()); } /** * Get node types * * @return Assoc */ function zzzz_ajax_types_node() { $out = array(); $types = node_get_types(); foreach ($types as $k => $v) { $out[$k . '_node_form'] = ucwords('Content Type: ' . $v->name); } return $out; } /** * Get module types. * This function currently unused. * * @return Assoc */ function zzzz_ajax_types_module() { $out = array(); $funcs = get_defined_functions(); foreach ($funcs['user'] as $f) { if (preg_match("/^([a-zA-Z0-9_]+?)_submit$/", $f, $func_name)) { $out[$func_name[1]] = ucwords(str_replace('_', ' ', $func_name[1])); } } return $out; } /** * Get other default types * * @return Assoc */ function zzzz_ajax_types_other() { return array( 'user_login' => 'User Login', 'user_edit' => 'User Edit', 'user_register' => 'User Register', 'comment_form' => 'Comment Form', 'logintoboggan_user_register' => 'Loggin Toboggan User Register' ); } /** * Get webform types * * @return Assoc */ function zzzz_ajax_types_webform() { $out = array();; $q = 'SELECT ' . ' n.nid, ' . ' n.title ' . 'FROM {node} n ' . 'WHERE n.type = "webform" '; $res = db_query($q); while ($row = db_fetch_array($res)) { $id = 'webform_client_form_' . (int) $row['nid']; $out[$id] = 'Webform: ' . $row['title']; } return $out; } /** * Display admin form * * @return Assoc */ function zzzz_ajax_admin() { $form = array( 'container_default' => array( '#type' => 'fieldset', '#title' => t('Default Forms'), '#collapsible' => TRUE, '#collapsed' => TRUE, 'ajax_types_default' => array( '#type' => 'select', '#multiple' => TRUE, '#options' => zzzz_ajax_types(), '#default_value' => variable_get('ajax_types_default', array()), '#size' => 20, '#description' => t( "Select the default forms you wish to use AJAX submissions.") ) ), 'container_custom' => array( '#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => TRUE, '#title' => t('Custom Forms (Advanced)'), 'ajax_types_custom' => array( '#type' => 'textarea', '#default_value' => variable_get('ajax_types_custom', ''), '#description' => t( 'Enter the form IDs of the custom forms you wish to ' . 'use AJAX Submissions. Enter one ID per line. Only alpha-numeric ' . 'characters should be used. ') ) ) ); return system_settings_form($form); } /** * hook_init * * @return Bool */ function zzzz_ajax_init() { drupal_add_js(drupal_get_path('module', 'zzzz_ajax') . '/Ajax.js', 'module'); return TRUE; } /** * Checks if form is a specified type * * @param $form_id String * @return Bool */ function zzzz_ajax_istype($form_id) { $exists = array_key_exists($form_id, variable_get('ajax_types_default', array())); if ($exists) { return TRUE; } else { $custom = variable_get('ajax_types_custom', FALSE); if ($custom !== FALSE) { $parts = preg_split("/[\r\n]+/", $custom, -1, PREG_SPLIT_NO_EMPTY); if ($parts) { foreach ($parts as $v) { if (trim($v) === $form_id) { return TRUE; } } } } return FALSE; } } /** * hook_form_alter * * @param $form Assoc * @param $form_state Assoc * @param $form_id String * @return Bool */ function zzzz_ajax_form_alter(&$form, $form_state, $form_id) { //watchdog('AJAX Forms', 'Form ID: %form_id', array('%form_id'=>$form_id)); if (zzzz_ajax_isType($form_id)) { $found = FALSE; zzzz_ajax_setcommentform($form, $form_id); zzzz_ajax_setlt($form); zzzz_ajax_setvalidator($form); zzzz_ajax_findsubmitter($form, $found); zzzz_ajax_setsubmitter($form, $found); } //print "
"; //print_r($form_state); //print ""; //print "
"; //print_r($form); //print ""; return TRUE; } /** * Handles a special case for Login Tobaggan redirection * * @param $form Assoc * @return Bool */ function zzzz_ajax_setlt(&$form) { global $logintoboggan_denied; if (isset($logintoboggan_denied) && $logintoboggan_denied) { $q = zzzz_ajax_pathinfo($form['#action']); if (!array_key_exists('destination', $q['query'])) { $p = zzzz_ajax_todrupalpath($form['#action']); $q['query']['destination'] = $p; $form['#action'] = url($p, array( 'query' => $q['query'], 'fragment' => $q['fragment'], 'absolute' => FALSE )); } } else { return FALSE; } } /** * Gets internal path from actual url path * This is needed for captcha forms * * @param $val String * @return String */ function zzzz_ajax_todrupalpath($val) { $b = base_path(); $bs = sizeof($b); if (substr($val, 0, $bs) === $b) { return substr($val, $bs); } else { return $val; } } /** * Collects path info * * @param $val String * @return Assoc */ function zzzz_ajax_pathinfo($val) { $out = array( 'path' => NULL, 'query' => array(), 'fragment' => NULL ); $u = parse_url($val); if (array_key_exists('query', $u)) { parse_str($u, $out['query']); } if (array_key_exists('path', $u)) { $out['path'] = $u['path']; } if (array_key_exists('fragment', $u)) { $out['fragment'] = $u['fragment']; } return $out; } /** * Enables the comment form * * @param $form Assoc * @param $form_id String * @return Bool */ function zzzz_ajax_setcommentform(&$form, $form_id) { if ($form_id === 'comment_form') { $form['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#weight' => 19 ); } return TRUE; } /** * Sets the validator * * @param $form Assoc * @return Bool */ function zzzz_ajax_setvalidator(&$form) { $form['#validate'][] = 'zzzz_ajax_validator'; return TRUE; } /** * Sets the submitter * * @param $form Assoc * @param $found Bool * @return Bool */ function zzzz_ajax_setsubmitter(&$form, $found) { if (!$found) { $form['#submit'][] = 'zzzz_ajax_submitter'; } return TRUE; } /** * Finds the submitter * * @param $form Assoc * @param $found Bool * @return Bool */ function zzzz_ajax_findsubmitter(&$form, &$found) { foreach ($form as $form_key => $form_val) { if (is_array($form[$form_key])) { //submit or preview button if ( (array_key_exists('#type', $form[$form_key]) && ($form[$form_key]['#type'] === 'submit' || $form[$form_key]['#type'] === 'button')) && ($form_key === 'submit' || $form_key === 'preview')) { $form[$form_key]['#attributes'] = array('onclick' => 'return Ajax.go(this);'); if (array_key_exists('#submit', $form[$form_key]) && !empty($form[$form_key]['#submit'])) { $form[$form_key]['#submit'][] = 'zzzz_ajax_submitter'; $found = TRUE; } } //nested else { zzzz_ajax_findsubmitter($form[$form_key], $found); } } } return TRUE; } /** * Gets redirect * Sometimes the redirect can be an array in the form of * 0 => path * 1 => query * 2 => fragment * * @param $redirect String|Array * @return String */ function zzzz_ajax_getredirect($redirect) { //watchdog('AJAX Forms', 'Redirect: !redirect', // array('!redirect'=>gettype($redirect[1]))); $args = array(); $args['absolute'] = TRUE; if (is_array($redirect)) { if ($redirect[1] !== NULL) { $args['query'] = $redirect[1]; } if ($redirect[2] !== NULL) { $args['fragment'] = $redirect[2]; } $path = $redirect[0]; } else { $path = $redirect; } return url($path, $args); } /** * Submission handler callback * * @param $form Assoc * @param $form_state Assoc * @return Bool */ function zzzz_ajax_submitter(&$form, &$form_state) { $data = array(); // Node Preview if (array_key_exists('node_preview', $form_state) && $form_state['node_preview'] !== NULL) { $data['preview'] = $form_state['node_preview']; } // Go to redirection page if (array_key_exists('redirect', $form_state) && $form_state['redirect'] !== NULL) { $data['redirect'] = $form_state['redirect']; } // Display messages internally without redirect else { $messages = drupal_get_messages(NULL, TRUE); if (array_key_exists('status', $messages)) { $data['messages_status'] = $messages['status']; } if (array_key_exists('warning', $messages)) { $data['messages_warning'] = $messages['warning']; } } $out = zzzz_ajax_build($data); zzzz_ajax_out($out); return TRUE; } /** * Validation handler callback * * @param $form Assoc * @param $form_state Assoc * @return Bool */ function zzzz_ajax_validator(&$form, &$form_state) { if (array_key_exists('ajax', $_REQUEST)) { drupal_get_messages(NULL, TRUE); $data = zzzz_ajax_build(array( 'messages_error' => form_get_errors() )); // Time to send messages if (!$data['status']) { zzzz_ajax_getcaptcha($form, $form_state, $data); zzzz_ajax_out($data); } // Special exception for the comment forms elseif ($form['form_id']['#value'] === 'comment_form' && $form['#post']['op'] === t('Preview')) { $data['preview'] = zzzz_ajax_comment_form_preview($form, $form_state); zzzz_ajax_out($data); } } return TRUE; } /** * Captcha functionality * This depends on the provided captcha patches * * @param $form Assoc * @param $form_state Assoc * @param $data Assoc * @return Bool */ function zzzz_ajax_getcaptcha(&$form, &$form_state, &$data) { if (array_key_exists('captcha_token', $form_state['values']) && array_key_exists('captcha_type', $form_state['values']) && array_key_exists('captcha_query', $form_state['values'])) { //print "YES"; if ($form_state['values']['captcha_type'] === 'math') { $selector = "#edit-captcha-response-wrapper .field-prefix"; $type = 'html_in'; } elseif ($form_state['values']['captcha_type'] === 'text') { $selector = "#edit-captcha-response-wrapper label[for='edit-captcha-response']"; $type = 'html_in'; } elseif ($form_state['values']['captcha_type'] === 'image') { $selector = ".captcha img"; $type = 'html_out'; } $data['updaters'][] = array( 'type' => 'field', 'selector' => '#edit-captcha-token', 'value' => $form_state['values']['captcha_token'] ); $data['updaters'][] = array( 'type' => $type, 'selector' => $selector, 'value' => $form_state['values']['captcha_query'] ); captcha_pre_render($form); } return TRUE; } /** * Grabs comment preview. * This function taken from comment_form_add_preview * * @param $form Assoc * @param $form_state Assoc * @return String */ function zzzz_ajax_comment_form_preview(&$form, &$form_state) { global $user; $edit = $form_state['values']; $output = ''; $node = node_load($edit['nid']); _comment_form_submit($edit); $comment = (object)$edit; // Attach the user and time information. if (!empty($edit['author'])) { $account = user_load(array('name' => $edit['author'])); } elseif ($user->uid && !isset($edit['is_anonymous'])) { $account = $user; } if (!empty($account)) { $comment->uid = $account->uid; $comment->name = check_plain($account->name); } elseif (empty($comment->name)) { $comment->name = variable_get('anonymous', t('Anonymous')); } $comment->timestamp = !empty($edit['timestamp']) ? $edit['timestamp'] : time(); if ($edit['pid']) { $comment = db_fetch_object(db_query( 'SELECT c.*, u.uid, u.name AS registered_name, ' . 'u.signature, u.picture, u.data FROM {comments} c ' . 'INNER JOIN {users} u ON c.uid = u.uid ' . 'WHERE c.cid = %d AND c.status = %d', $edit['pid'], COMMENT_PUBLISHED)); $comment = drupal_unpack($comment); $comment->name = $comment->uid ? $comment->registered_name : $comment->name; } else { $suffix = empty($form['#suffix']) ? '' : $form['#suffix']; $form['#suffix'] = $suffix . node_view($node); $edit['pid'] = 0; } $output = '