Thanks for Flag, it's one of my absolute favourite modules, I switch it on for every Drupal site.

I am developing an extension module for Flag called Flag Plus (flagplus).

It's in the sandbox at https://drupal.org/sandbox/webel/2398617 with a partial description, and there is a more detailed description at its external module homepage at http://drupal7demo.webel.com.au/module/flagplus, which already includes some images showing the extended features.

One of the Flag Plus features is banner strips for flagged (and NOT flagged) node content, with easily styled colors and messages, per flag.

When one uses the Flag AJAX links to flag or unflag a node, I need to be able to reload the node to show the updated Flag Plus banners.

I examined your examples for updating a Block (not quite what I am after, but close) at The Flag API (JavaScript). Those examples, with additional JavaScript, require the Component module, which is not available for Drupal7.

The View Flag Refresh views approach suggested there does not meet my requirements, as I am not using a view for the Flag Plus banners, I am using hook_node_view($node, $view_mode, $langcode).

I am willing to use some custom JavaScript if necessary, but I am trying first to use existing Drupal7 AJAX and Ctools AJAX first in hook_flag_flag/unflag.

I am delegating both hooks thus:

function flagplus_flag_flag($flag, $content_id, $account, $flagging) {
  _flagplus_ajax_reload_page($content_id);
}

function flagplus_flag_unflag($flag, $content_id, $account, $flagging) {
  _flagplus_ajax_reload_page($content_id);  
}

I have tried all of the following without success. I am fluent with Drupal7's system for Partial Page Update AJAX commands and Form API AJAX support, but I don't understand how to reload the node without disrupting the Flag AJAX link cycle.

Use ajax_command_replace on '#content' or 'div.content':

function _flagplus_ajax_reload_page($content_id) {
  // Load Drupal core AJAX library.
  drupal_add_library('system', 'drupal.ajax');
  drupal_add_js('misc/jquery.form.js');

  // Check whether exists as a node and theme it.
  $node = node_load($content_id);
  if ($node) {
    
    $vnode = node_view($node);
    $vnode_themed = theme('node', $vnode);
    
    // An AJAX command that replaces the page #content.
    $selector = '#content'; // FAILS
    //$selector = 'div.content'; //FAILS
    $html_replace = $vnode_themed;
    // Optional: $settings.
    $commands[] = ajax_command_replace($selector, $html_replace);
    $page = array(
      '#type' => 'ajax',
      '#commands' => $commands
    );
    ajax_deliver($page);
  }  
}

Gives error:

An HTTP error 200 occurred.
.../flag/unflag/resolved/46?destination=node/46&token=...

This fails:

function _flagplus_ajax_reload_page($content_id) {   
  $node = node_load($content_id);
  if ($node) {
    drupal_goto("node/$content_id");
  }  

This using Ctool fails similarly:

function _flagplus_reload_page($content_id) {
  
  ctools_include('ajax');
  ctools_ajax_command_reload();//FAILS
 }

As does this:

function _flagplus_reload_page($content_id) {
  
  ctools_include('ajax');
   
  // Just to check whether exists as node
  $node = node_load($content_id);
  
  if ($node) {
    ctools_ajax_command_redirect("node/$content_id");//FAILS
  }  
}

I also read 4th option - JS refresh node, which seems to ask something similar, but does not seem to include the answer.

Glad for any feedback,

Webel

Comments

webel’s picture

Issue summary: View changes
webel’s picture

Issue summary: View changes
joachim’s picture

> Those examples, with additional JavaScript, require the Component module, which is not available for Drupal7.

It looks to me like those examples use Component, but just to illustrate the method. You don't *need* Component module for this, you just need a module that supplies a rendered block that your AJAX can retrieve to replace in the current page.

If you're trying to use ctools_ajax_command_reload(), which according to the docs forces a reload of the current page, then why not just set the Flag to use the normal link, which reloads the whole page normally? Getting JS to reload the whole page for you is just complicating things.

webel’s picture

Status: Active » Postponed

@joachim Thanks for reply.

> you just need a module that supplies a rendered block that your AJAX can retrieve to replace in the current page.

Rendered node.

> why not just set the Flag to use the normal link, which reloads the whole page normally?
> Getting JS to reload the whole page for you is just complicating things.
Merely so that users of Flag Plus don't have to change the way they use Flag.

Please permit me to postpone (not end) this issue while I explore some other Drupal7 AJAX partial page update/render techniques that might work, will report back here.

joachim’s picture

BTW, I've figured out why the CTools approach isn't working

ctools_ajax_command_reload() is returning an AJAX command (https://api.drupal.org/api/drupal/includes!ajax.inc/group/ajax/7). (Its docs should really state that!)

You're not doing anything with that -- you're just throwing it away. And you can't do anything useful with it from hook_flag_flag() anyway -- you're not somewhere where you even get anything rendered out.

You would need to act at the point where Flag is returning things to the browser. And even then, I suspect that Flag is returning flat HTML for Flag's own JS to insert, because the JS in Flag module hasn't been changed since the days of 6.x (at least), and AJAX commands are new in D7.

joachim’s picture

> I suspect that Flag is returning flat HTML for Flag's own JS to insert

Yup, confirming that's the case.

It might be feasible to change Flag to use core's AJAX framework -- we'd have to see how much change to things like theming is involved.

joachim’s picture

Hmmm, but even then, I think it would be the wrong approach, because you'd be returning an AJAX command to reload the page (or the node). So the user would see a sequence of two AJAX loads, and you'd get two hits on the server.

I think what you need is to replace the normal Flag JS with something that knows to reload the whole thing. That's either going to take some fancy footwork, or your module should provide a new flag link type that should be used instead of the core JS link.

webel’s picture

@joachim Thanks have read and considered all of your feedback.

> ' .. or your module should provide a new flag link type that should be used instead of the core JS link.'

That might be the way ahead, will look into it.