I've beening reading support issues on how to impliment the modal windows and still haven't been able to do so for the comment form. I should note by comment form I mean the reply comment form.

So here's what I have...

First I altered the reply link

function fp_comment_link_alter(&$links, $node, $comment = NULL) {
// Load the Ctools modal library and add the modal javascript.
ctools_include('modal');
ctools_modal_add_js();
$links['comment_reply']['title'] = t('Reply');
$links['comment_reply']['weight'] = 10;
// Alter the reply link so we can use the Ctools modal dialog window.
$links['comment_reply']['href'] = "comment/reply/$comment->nid/$comment->cid/nojs/go";
$links['comment_reply']['attributes'] = array('class' => 'ctools-use-modal');
}

Followed by creating a menu

function fp_comment_menu() {  
  $items['comment/reply/%node/%ctools_js'] = array(
    'page callback' => 'fp_comment_comment_reply',
    'page arguments' => array(2, 3),
    'access arguments' => array('post comments'),
  );
  return $items;
}

Then I made the page callback

function fp_comment_comment_reply($js = FALSE) {

  if ($js) {
    ctools_include('modal');
    ctools_include('ajax');
    $form_state = array(
      'ajax' => TRUE,
      'title' => t('Reply to Comment'),
    );
    $output = ctools_modal_form_wrapper('comment_form', $form_state);
    if (empty($output)) {
      $output[] = ctools_modal_command_display('Thank you for you comment.');
    }
    ctools_ajax_render($output);
  } else {
    return drupal_get_form('comment_form');
  }
}

When the form loads I get an error...
Unable to complete operation. Fatal error in C:\websites\freedomspress\modules\comment\comment.module on line 1254: Unsupported operand types

So I tried to fix that... Although I had no clue what I was doing. I think I took out the + sign on line 1245. Which made that error go away but another error about missing arguements appeared. So I quickly stopped and came here for help.

Thanks.

Comments

walker2238’s picture

Status: Active » Closed (fixed)

Dialog seems to do the same thing from what I have read. I'll try that out.

minff’s picture

Version: 6.x-1.6 » 7.x-1.0-alpha2
Status: Closed (fixed) » Active

I'm trying to do the exact same thing as the previous poster half a year ago. Only on D7, not D6.
Here's the function I have:

function comment_popup_open($nid, $js = NULL) {
  $node = node_load($nid);
  $edit = array('nid' => $node->nid);
  if (!$js) {
    return drupal_get_form('comment_node_'.$node->type.'_form', (object)$edit);
  }
  ctools_include('modal');
  ctools_include('ajax');
  $form_state = array(
    '#edit' => $edit,
    'title' => 'Add a comment ('.$node->type.')',
    'ajax' => TRUE,
  );
  $output = ctools_modal_form_wrapper('comment_node_'.$node->type.'_form', $form_state);
  if (empty($output)) {
    $output = array();
    $output[] = ctools_modal_command_display('Success', '<div class="modal-message">Comment added!</div>');
  }
  print ajax_render($output);
  exit;
}

This code outputs a comment form, but not the one of the particular node type. That is, it outputs 2 fields (name and topic), while it should output name and comment textarea (and no topic field). When posted, a 404 error is shown (because form action=comment/reply/ for some reason).
Any help or suggestions are welcome!

minff’s picture

Status: Active » Fixed

Ok, I got that one myself: I hadn't given the page info the right way. Thus, instead of '#edit' => $edit, one needs 'comment' => (object)$edit.

minff’s picture

Status: Fixed » Active

Yet, problems persist. Although the form is ok now, when submitting, HTML of the success page is shown in JS alert. No Ajax is performed from that point to change the output of the modal window. The comment, however, is added.
Also, what is interesting, in dblog the following error of comment_form() is shown:
Warning: Missing argument 3 for comment_form() in function comment_form() (row 1835 in /modules/comment/comment.module).
That is, the comment form is not called properly by ctools_modal_form_wrapper(). Am I still missing some arguments that need to go into $form_state array when dealing with comments?

merlinofchaos’s picture

It should no longer check for empty $output. Instead, check for $form_state['submitted'] to see if the form was successfully submitted and processed.

merlinofchaos’s picture

Also, hm. It's possible you may have to adjust the $form['#action'] if the original form wants to submit somewhere else. That may be one of the difficulties of trying to override the comment form here.

minff’s picture

As the $form['#action'] was indeed directing elsewhere (i.e. comment/reply/NID), then I swapped it for a custom page/function using hook_form_alter(). But the problem is in getting the form info in order to process the saving part. ajax_form_callback() gives me "Invalid form POST data" error, meaning that the form isn't cached when generated, or the build_id is wrong for some reason. Or does Ctools have an equivalent for ajax_form_callback()? (as it doesn't use the '#ajax' parameter in that form)

Or would there be a way to still use the same form action but snatch the info for Ajax before the page reloads?

PS. The warning given in #4 still persists: comment_form() is not getting its third argument ($comment) for some reason.

minff’s picture

Ok, here's a working code with some "buts":

function comment_popup_open($nid, $js = NULL) {
  $node = node_load($nid);
  // setting these defaults is needed, otherwise warnings result in dblog
  $edit = array('nid' => $node->nid, 'name' => '', 'mail' => '', 'homepage' => '', 'subject' => '', 'comment' => '', 'cid' => NULL, 'pid' => NULL, 'language' => LANGUAGE_NONE, 'uid' => 0);
  if (!$js) {
    return drupal_get_form('comment_node_'.$node->type.'_form', (object)$edit);
  }
  ctools_include('modal');
  ctools_include('ajax');
  $form_state = array(
    'comment' => (object)$edit,
    'title' => 'Add comment ('.$node->type.')',
    'ajax' => true,
    'cache' => true // setting this solved the problem of not getting the form data from ajax_get_form()
  );
  $output = ctools_modal_form_wrapper('comment_node_'.$node->type.'_form', $form_state);
  print ajax_render($output);
  exit;
}

function comment_popup_form_alter(&$form, $form_state, $form_id) {
  if ($form['#id'] == 'comment-form' and isset($form_state['ajax']) and $form_state['ajax'] == true) {
    $form['#action'] = 'comment_popup/nojs/comment_add';
  }
}

function comment_popup_comment_add($js = NULL) {
  list($form, $form_state) = ajax_get_form();
  drupal_process_form($form['#form_id'], $form, $form_state);
  $_POST = array();
  ctools_include('modal');
  ctools_include('ajax');
  $output = array();
  $output[] = ctools_modal_command_display('Done!', '<div class="modal-message">Comment added!</div>');
  print ajax_render($output);
  exit;
}

It's obviously not the best piece of code ever written, but I'm still working on it. (And at least it works.) Suggestions on how to do it more gracefully are much appreciated.

Todo: handling messages and errors, closing the modal and scrolling to the newly added comment in the main window.

What is weird, though, the warning referred to in #4 persists.

lord_of_freaks’s picture

suscribing

merlinofchaos’s picture

Status: Active » Fixed

Ahh, to get rid of that warning you might need to set...I think it's $form_state['build_args'] in D7. Check the documentation for drupal_get_form().

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

ranvir.prasad’s picture

Version: 7.x-1.0-alpha2 » 6.x-1.8

Well, I also struggled a lot and finally managed to accomplish by doing the following:

<?
function fp_comment_comment_reply($js = FALSE) {

if ($js) {
ctools_include('modal');
ctools_include('ajax');
$edit=array();
$edit['nid']=$nid;
$form_state = array(
'ajax' => TRUE,
'title' => t('Reply to Comment'),
'args'=>array($edit),
);

$output = ctools_modal_form_wrapper('comment_form', $form_state);
if (empty($output)) {
$output[] = ctools_modal_command_display('Thank you for you comment.');
}
ctools_ajax_render($output);
} else {
return drupal_get_form('comment_form');
}
}
?>
Ironflood’s picture

i'm trying to create the same functionality, under D7.
Minff and merlin's comments helped a lot, but i still can't figure out the issue with the AJAX warning that i believe has been described at #4.

I followed Minff code suggestion.
The comment is successfully posted, however I get a:

"Warning: Parameter 1 to dialog_comment_comment_view() expected to be a reference, value given in module_invoke_all() (line 819 of ...\includes\module.inc)."

Did anyone solved the issues mentionned in minff's posts? Does anyone has a solution or walkthrough on this?

Thx!

Ironflood’s picture

Version: 6.x-1.8 » 7.x-1.0-beta1
Status: Closed (fixed) » Needs review

Edit: it's on the latest version of ctools

merlinofchaos’s picture

Status: Needs review » Active

Please reserve 'needs review' for patches to the module.

minff’s picture

What does the function that gives the error (i.e. dialog_comment_comment_view()) do? (It's not the same error described in #4.) Have you done the hook_menu() implementation correctly? It should look something like that:

  $items['comment_popup/%/%ctools_js/comment'] = array(
      'title' => 'Add comment',
      'page callback' => 'comment_popup_open',
      'page arguments' => array(1, 2),
      'access callback' => TRUE,
      'type' => MENU_CALLBACK,
  );
  $items['comment_popup/%ctools_js/comment_add'] = array(
      'title' => 'Post-adding Action',
      'page callback' => 'comment_popup_comment_add',
      'page arguments' => array(1),
      'access callback' => TRUE,
      'type' => MENU_CALLBACK,
  );

Unfortunately the project I needed this for is now on hold (and down), so I don't have a working example anywhere. But as much as I remember it did not give any warnings or errors any more. The only problem I encountered was closing the modal, refreshing comments using Ajax and scrolling to the newest one. But otherwise everything worked.

Ironflood’s picture

Version: 7.x-1.0-beta1 » 7.x-1.0-rc1

Thanks Minff for your answer, i correctly made the menu implementation yes.

The error I still cannot get rid is an AJAX error. The DB log shows nothing. The comment is perfectly added but it seems I'm still facing AJAX error on form submission. AJAX HTTP 200
I tried for weeks to make it work but without success, would it be a module conflict?

Anyone has a walkthrough on posting a comment through a Ctools modal on D7?

couturier’s picture

I'm working on this myself currently with the help of another programmer. If we find any solutions, we'll let you know. In the meantime, has anyone had further success with this?

Ironflood’s picture

I couldn't get rid of the AJAX errors, I must have missed something.
The easy solution was finally to create a form manually displayed in modal, and then to create a new comment programmatically by passing the data gathered by the form.

couturier’s picture

I and a programmer from my local DUG have been working on this, and like you, Ironflood, we are getting AJAX errors with the codes suggested above. Would you be willing to share the code you used to get the modal to work, including the modal link itself? I've scoured CTools documentation and cannot find anything to help other than this thread.

One idea, since our node content is just a small paragraph and photo displayed with many other nodes in a Views table, is to target the modal link to the whole node, then any existing comments plus the comment reply form would appear together. The programmer who is helping me in his spare time has come up with a way to add an option to Views to create a modal link. He will contribute this when it is ready, but there are still bugs to work out and he has to find spare time to continue work on it, so it could be a few more months.

barakgalili’s picture

this line before ctools_modal_form_wrapper will fix the error
$form_state['build_info']['args'][] = (object)$edit;

waaadim’s picture

hello, let's do it quick :)

i found this example ---> http://zroger.com/2009/12/ajax-modal-windows/ but i can not get the form to load in the modal window.

my code looks like this:

function mymodule_quote_test_modal_callback($js = FALSE) {
  ctools_include('ajax');
  ctools_include('modal');
  $form_state = array(
    'ajax' => TRUE,
    'title' => t('My title'),
  );
  $output = ctools_modal_form_wrapper('myform_quote', $form_state);
  //$output here contains the rendered form
  ctools_modal_render('title', $output);
}

//core functions
function ctools_modal_render($title, $output) {
  $commands = array();
  $commands[] = ctools_modal_command_display($title, $output);
  //$commands[0]['output'] is NULL :(
  dsm($commands,'coms');
  print ajax_render($commands);
}

//this function is called twice the first time it gets a string with the already rendered form
//the second time it gets an array similar to the returned array
function ctools_modal_command_display($title, $html) {
  dsm($html, 'html');
  if (is_array($html)) {
    $html = drupal_render($html);
  }
    // if i hard code my form here ->  $html = '<form .... '; the form is printed and everything is nice, except the fact that i can not validate/submit it.

  dsm($html, 'rendered_html');
  return array(
    'command' => 'modal_display',
    'title' => $title,
    'output' => $html,
  );
}

please feel free to comment

couturier’s picture

This issue is for bringing up the comment form (or a node with the comment form below it) in the modal window. By the way, Mimmoo, I tried the code in #21 and did not see a difference. I would still love to see Ironflood's code from #19, including the format for the link to activate the modal.

Waaadim, if you are interested in bringing up a plain form in the modal window, I think that is much easier. I recommend installing the Modal Forms module and working based on those examples or reading documentation in the CTools Ajax examples and modal.inc and other CTools includes files for help.

Ironflood’s picture

Couturier, crafting the proper link to the modal is quite straight forward from CTools AJAX example.
I'll list you what needs to be done if you were going in the same direction: create a new comment programmatically by passing the data gathered by the form.
Note: This is a part of my code, this is far from being the best piece of code ever written!

You can put the following in a block for example, this part crafts the link:
(The $nid allows us later on the know which node the comment should be attached to)

                  //Taken From CTools AJAX examples
		  ctools_include('ajax');
		  ctools_include('modal');
		
		  // Add CTools' javascript to the page.
		  ctools_modal_add_js();
		
		  // Create our own javascript that will be used to theme a modal.
		  $sample_style = array(
		    'ctools-sample-style' => array(
		      'modalSize' => array(
		        'type' => 'fixed',
		        'width' => 580,
		        'height' => 350,
		        'addWidth' => 20,
		        'addHeight' => 15,
		      ),
		      'modalOptions' => array(
		        'opacity' => .5,
		        'background-color' => '#000',
		      ),
		      'animation' => 'fadeIn',
		      'modalTheme' => 'CToolsSampleModal',
		      //'throbber' => theme('image', array('path' => ctools_image_path('ajax-loader.gif', 'MYMODULE'), 'alt' => t('Loading...'), 'title' => t('Loading'))),
		    ),
		  );
		
      drupal_add_js($sample_style, 'setting');
      // Since we have our js, css and images in well-known named directories,
      // CTools makes it easy for us to just use them without worrying about
      // using drupal_get_path() and all that ugliness.
      ctools_add_js('ctools-ajax-sample', 'MYMODULE');
      ctools_add_css('ctools-ajax-sample', 'MYMODULE');

          $url = 'modal/' . $nid . '/comment' . '/nojs';
          // Create a list of clickable link(s).
          $links = array();
          $links[] = ctools_modal_text_button(t('Link to modal'), $url, t('title'),  'ctools-modal-ctools-sample-style');
          $output = theme('item_list', array('items' => $links));
          return array('markup' => array('#markup' => $output));

Now use drupal hook menu in MYMODULE.module to define the callback:

  $items['modal/%/comment/%ctools_js'] = array(
      //'title' => 'Write Comment',
      'page callback' => 'modal_frame_callback',
      'page arguments' => array(1,3),
      'file' => 'inc/MYMODULE_modalframe.inc',
      'type' => MENU_CALLBACK,
  );

Finally, write the callback that exposes a custom form

function modal_frame_callback($nid = NULL, $js = NULL) {
  global $user; //Get the user info in an array
  
  //Test whether we are in ajax environment
  if ($js) {
    ctools_include('modal');
    ctools_include('ajax');
  }

  $form_state = array(
      'title' => t('Write Comment'),
      'ajax' => TRUE,
  );

  //$form_state['args']['nodeid']= $nid;

  $output = ctools_modal_form_wrapper('form_modal_write_comment', $form_state); //See the forms below
 
 if (!empty($form_state['executed'])) 
 {
    // We'll just overwrite the form output if it was successful.
    $output = array();

    $output[] = ctools_modal_command_dismiss();
   
    print ajax_render($output);
}

function form_modal_write_comment($form, &$form_state)
{
    $form['title'] = array(
      '#type'  => 'textfield',
      '#title' => t('Comment Title:'),
      '#required' => TRUE,
    );
    $form['body'] = array(
       '#type' => 'textarea',
       '#title' => t('Comment Body'),
    );
}

//Validation function to make sure the user's entry is correct
function form_modal_write_comment_validate($form, &$form_state) {
  $title= $form_state['values']['title'];
  if (empty($title)) {
    form_set_error('title', t('Enter a title'));
  }
}

function form_modal_write_comment_submit($form, &$form_state)
{
  $body = check_plain($form_state['values']['body']);
  $title = check_plain($form_state['values']['title']);
   
  // Add a comment, and configure the first easy fields.
  $comment = (object) array(
    'nid' => $nid,
    'cid' => NULL,
    'pid' => NULL,
    'uid' => $user->uid,
    'mail' => '',
    'is_anonymous' => 0,
    'homepage' => '',
    'status' => COMMENT_PUBLISHED,
    'language' => LANGUAGE_NONE,
  );
 $comment->['subject'] = $title;

 if(!empty($body) || $term->body != ''){
    $comment->comment_body[LANGUAGE_NONE][0]['value']=check_plain($body);
    $comment->comment_body[LANGUAGE_NONE][0]['format']='plain_text';
  }
  comment_submit($comment);
  comment_save($comment);
}

Hope this draft helps you!

couturier’s picture

Ironflood, I wanted to be sure to get back with you and say THANKS so much for taking time to document your work for us here. I am sure that it will be of help to programmers who are referencing this issue for help with modals. For myself--a non-programmer--I did give your code a try, but with my limited knowledge of php was not able to implement it successfully to my site. In light of my other time obligations this year, I have decided that it is best to shelve this project rather than taking the weeks that I would need to acquire adequate coding skills for this task.

Another programmer who offered to help me was not able to achieve the desired outcome quickly on a test site we set up (I wanted comment form modals to pop up from Views tables). He had to move on to other work but told me that he may re-visit the concept in the future for one of his own sites, in which case he would let me know and give me the code. My hope now is that if I wait long enough, modals may be simplified with an API into a future release of CTools. One comment from merlinofchaos on a related thread summed up what I feel is the complexity of working with coding for modals.

Node forms are very complicated. What you're doing is not a common task. Modals and javascript are complicated. Putting it all together can be tough. And to be honest, not that many people really are able to provide support in the CTools queue. Maybe stackoverflow would've gotten you more eyeballs.

Yes, everything should be simple, but when you start breaking things down into components, what seems simple really isn't.

I'm sorry you were so frustrated with this, though. Things are made tougher by the difficulty of documenting FAPI and the fact that node forms are a pretty difficult implementation of FAPI due to history.

shivams’s picture

Well, there's a module for that.

http://drupal.org/project/modal_forms

Saved me a lot of hassle. Autmagically converted the links to load modal forms.

couturier’s picture

The Modal Forms project is different and much more simple than putting the Comment Reply Form in a modal. One is static, the other dynamic.

keopx’s picture

Issue summary: View changes
v8powerage’s picture

Where should I put code from https://www.drupal.org/node/828794#comment-4318936 #12?

plazik’s picture

Version: 7.x-1.0-rc1 » 7.x-1.x-dev

Working example for "product" node type:

mymodule.module

<?php

/**
 * @file
 * TODO
 */

/**
 * Implements hook_menu().
 */
function mymodule_reviews_menu() {
  $items = array();

  $items['add-review/%ctools_js/%node'] = array(
    'title' => 'Add new review for product',
    'page callback' => 'mymodule_reviews_add_review_callback',
    'page arguments' => array(1, 2),
    'access arguments' => array('access content'),
    'delivery callback' => 'ajax_deliver',
    'theme callback' => 'ajax_base_page_theme',
  );

  return $items;
}

/**
 * Implements hook_ds_fields_info().
 */
function mymodule_reviews_ds_fields_info($entity_type) {
  $fields = array();

  $fields['add_review'] = array(
    'title' => 'Add review',
    'field_type' => DS_FIELD_TYPE_FUNCTION,
    'ui_limit' => array('product|*'),
    'function' => 'mymodule_reviews_ds_add_new_review',
  );

  return array('node' => $fields);
}

/**
 * Callback to Add Review DS button.
 */
function mymodule_reviews_ds_add_new_review() {
  $nid = arg(1);
  if (is_numeric($nid)) {
    return ctools_modal_text_button(t('Add review'), 'add-review/nojs/' . $nid, t('Add review'), 'ctools-modal-add-review-style');
  }
  else {
    return FALSE;
  }
}

/**
 * Callback for add review.
 */
function mymodule_reviews_add_review_callback($js = NULL, $node) {
  if (!$js) {
    drupal_goto('<front>');
  }
  if (!isset($node->nid)) {
    drupal_goto('<front>');
  }

  ctools_modal_add_js();
  ctools_include('ajax');

  $form_state = array(
    'title' => t('Add review'),
    'ajax' => TRUE,
    'build_info' => array(
      'args' => array(
        (object) array(
          'nid' => $node->nid,
          'node_type' => 'comment_node_product',
        ),
      ),
    ),
  );

  form_load_include($form_state, 'inc', 'comment', 'comment.pages');
  $commands = ctools_modal_form_wrapper('comment_node_product_form', $form_state);

  if (!empty($form_state['executed'])) {
    $commands = array();
    $commands[] = ctools_modal_command_display(t('Review'), '<div class="messages status">' . t('Review has been added.') . '</div>');
    $commands[] = ajax_command_remove('#messages');
    $commands[] = ajax_command_replace('#messages-placeholder', '' . theme('status_messages') . '');
  }

  return array('#type' => 'ajax', '#commands' => $commands);

}

/**
 * Ctools styles for bit popup for change city.
 */
function _mymodule_reviews_add_review() {
  static $added = FALSE;
  if ($added == FALSE) {
    $added = TRUE;

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

    // Add CTools' javascript to the page.
    ctools_modal_add_js();

    $style = array(
      'add-review-style' => array(
        'modalSize' => array(
          'type' => 'fixed',
          'width' => 580,
          'height' => 580,
          'addWidth' => 20,
        ),
        'modalOptions' => array(
          'opacity' => 0.7,
          'background-color' => '#000',
        ),
        'closeText' => 'X',
        'loadingText' => 'Loading',
        'animation' => 'fadeIn',
        'modalTheme' => 'MymoduleCToolsAddReview',
        'animationSpeed' => 'fast',
      ),
    );

    drupal_add_js($style, 'setting');

    ctools_add_js('mymodule-reviews-add-review', 'mymodule_reviews');
  }
}


function mymodule_reviews_preprocess_node(&$variables) {
  if ($variables['view_mode'] == 'full') {
    $node = $variables['node'];
    if ($node->type == 'product') {
      _mymodule_reviews_add_review();
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function mymodule_reviews_form_comment_node_product_form_alter(&$form, &$form_state, $form_id) {
  $form['actions']['preview']['#access'] = FALSE;
  $form['author']['homepage']['#access'] = FALSE;
  unset($form['author']['mail']['#description']);
  $form['actions']['submit']['#value'] = t('Add review');
  $form['#action'] = '/add-review/nojs/' . $form['#node']->nid;
}

js/mymodule-reviews-add-review.js

/**
 * Provide the HTML to create the modal dialog.
 */
Drupal.module.prototype.MymoduleCToolsAddReview = function () {
  var html = '';

  html += '<div id="ctools-modal">';
  html += '  <div class="ctools-modal-content ctools-city-change-big">';
  html += '    <div class="popups-container">';
  html += '      <div class="modal-header popups-title">';
  html += '        <span id="modal-title" class="modal-title"></span>';
  html += '        <span class="popups-close"><a class="close" href="#">' + Drupal.CTools.Modal.currentSettings.closeText + '</a></span>';
  html += '      </div>';
  html += '      <div class="modal-scroll"><div id="modal-content" class="modal-content popups-body"></div></div>';
  html += '    </div>';
  html += '  </div>';
  html += '</div>';

  return html;

};
mustanggb’s picture

Status: Active » Closed (outdated)