My dynamic update from js to callback to php cause my form to load over and over and over again - not reload, but recursive like.

JS function pings callback on interval:

setInterval(function() {
  $.get(Drupal.settings.basePath + 'node/' + Drupal.settings.mobwrite.nid + '/edit/mobwrite/participant/' +
    Drupal.settings.mobwrite.shareGroup + '/' + Drupal.settings.mobwrite.uid, function(data) {
      $('#mobwrite-participants').replaceWith(data);
  });
}, 1500);

The callback is mapped to a PHP function that returns data and sets a uid and timestamp in custom tables. The actual URL will would look something like, "mw/node/1/edit/mobwrite/participant/mobwrite-Eu8yoBZ_tgvLFxyaurL3b53OVhldkGu4vcDiLkz7uNQ/2" - the last two are key and uid:

<?php
  // callback to access mobwrite participant functions
  $items['node/%node/edit/mobwrite/participant'] = array(
    'page callback' => 'mobwrite_participant',
    'page arguments' => array(1),
    'access callback' => 'mobwrite_node_update_access',
    'access arguments' => array(1),
    'type' => MENU_CALLBACK,
    'file' => 'mobwrite.func.inc',
  );
?>

And finally, mobwrite_participant():

<?php
function mobwrite_participant($nid = NULL, $key = NULL, $uid = NULL) {

  // authenticate $key
  if ($key != mobwrite_variable_get('share_group_node_' . $nid, NULL)) {
  //if (false) {
    drupal_set_message(t('The key provided does not match the MobWrite Session:') . '<br>' . $key, 'status', TRUE);
    drupal_goto('node/' . $nid, drupal_get_destination());
  }

  // merge the passed UID
  db_merge('mobwrite_participants')
    ->key(array('uid' => $uid, 'nid' => $nid))
    ->fields(array('timestamp' => REQUEST_TIME))
    ->execute();

  // remove expired participants
  db_delete('mobwrite_participants')
   ->condition('timestamp', REQUEST_TIME - 30, '<')
   ->execute();

  // gather up participants for return
  $query = db_select('mobwrite_participants', 'mp');
  // join with users table to get the participant's username
  $query->join('users', 'u', 'mp.uid = u.uid');
  // add participant  fields
  $query->addField('mp', 'uid');
  $query->addField('mp', 'nid');
  // add username fields
  $query->addField('u', 'name');
  // set the condition to be uids assoc with nid
  $query->condition('mp.nid', $nid);
  // order by who has been there the longest
  $query->orderBy('mp.timestamp', 'DESC');
  // catch the results of the query
  $results = $query->execute();

  // start our formated output
  $output = '<div id="mobwrite-participants">';
  $output .= '<ul>';
  //now find our users
  foreach ($results as $record) {
    $output .= '<li>' . theme('username', array('account' => $record)) . '</li>';
  }
  // close the markup
  $output .= '</ul></div>';

  exit($output);
} // mobwrite_participant()
?>

Comments

tomdavidson’s picture

Priority: Major » Normal
Status: Postponed » Postponed (maintainer needs more info)

no longer experiencing... appears to have been an issue of typos in the menu_callback.

tomdavidson’s picture

Reorganizing the code, namely wrapping the setInterval into a function that is called only when there is a sharing session in progress rather than on page load, has caused the symptoms to resurface. Watching the console of my browser I see that node/%node is often being got rather that then entire URL for the callback that would look something like
"mw/node/1/edit/mobwrite/participant/mobwrite-asdlfjasldkfjasldajksdw20389203sdfjal/2". By using the alert and path seen below, I have verified the the correct and entire path is being passed to $.get().

JS Function:

function mobwriteParticipant() {
    participantIntervalID = setInterval(function() {
      var path = Drupal.settings.basePath + 'node/' + Drupal.settings.mobwrite.nid + '/edit/mobwrite/participant/' +
        Drupal.settings.mobwrite.shareGroup + '/' + Drupal.settings.mobwrite.uid;
      //alert(path);
      $.get(path, function(data) {
          $('#mobwrite-participants').replaceWith(data);
      });
    }, 3000);
  } // mobwriteParticipant()

Updated callback:

<?php
  $items['node/%node/edit/mobwrite/participant'] = array(
    'page callback' => 'mobwrite_participant',
    'page arguments' => array(1, 5, 6),
    'access callback' => TRUE, //'mobwrite_node_update_access',
    'access arguments' => array(1, 5),
    'type' => MENU_CALLBACK,
    'file' => 'mobwrite.func.inc',
  );
?>
tomdavidson’s picture

Priority: Normal » Major
Status: Postponed (maintainer needs more info) » Active
lyricnz’s picture

If you use %node in the path, that will call node_load() on the nid, and pass $node to your function. So the first argument will be $node not $nid. Then your first if() statement will probably be executed, which causes a redirect.

tomdavidson’s picture

Sorry, I should have also posted the updated PHP function that address the issue presented by lyricnz:

<?php
function mobwrite_participant($node = NULL, $key = NULL, $uid = NULL) {
  $nid = $node->nid;

  // authenticate $key
  if ($key != mobwrite_variable_get('share_group_node_' . $nid, NULL)) {
    drupal_set_message(t('The key provided does not match the MobWrite Session:') . '<br>' . $key, 'status', TRUE);
    drupal_goto('node/' . $nid, drupal_get_destination());
  }

  // merge the passed UID
  db_merge('mobwrite_participants')
    ->key(array('uid' => $uid, 'nid' => $nid))
    ->fields(array('timestamp' => REQUEST_TIME))
    ->execute();

  // remove expired participants
  db_delete('mobwrite_participants')
   ->condition('timestamp', REQUEST_TIME - 15, '<')
   ->execute();

  // gather up participants for return
  $query = db_select('mobwrite_participants', 'mp');
  // join with users table to get the participant's username
  $query->join('users', 'u', 'mp.uid = u.uid');
  // add participant  fields
  $query->addField('mp', 'uid');
  $query->addField('mp', 'nid');
  // add username fields
  $query->addField('u', 'name');
  // set the condition to be uids assoc with nid
  $query->condition('mp.nid', $nid);
  // order by who has been there the longest
  $query->orderBy('mp.timestamp', 'DESC');
  // catch the results of the query
  $results = $query->execute();

  // start our formated output
  $output = '<div id="mobwrite-participants">';
  $output .= '<ul>';
  //now find our users
  foreach ($results as $record) {
    $output .= '<li>' . theme('username', array('account' => $record)) . '</li>';
  }
  // close the markup
  $output .= '</ul></div>';

  exit($output);
} // mobwrite_participant()
?>
tomdavidson’s picture

Priority: Major » Normal

With the proper info posted, Berdir on IRC saw the problem lay with mobwrite_participant()'s use of drupal_goto(). The current, temperary, work around is as follows:

<?php
function mobwrite_participant($node = NULL, $key = NULL, $uid = NULL) {
  $nid = $node->nid;

  // authenticate $key
  if ($key != mobwrite_variable_get('share_group_node_' . $nid, NULL)) {
    // @todo drupal_goto messes stuff up in a way I do not understand :)
    //drupal_set_message(t('The key provided does not match the MobWrite Session:') . '<br>' . $key, 'status', TRUE);
    //drupal_goto('node/' . $nid, drupal_get_destination());
    exit(t('No participants were found because the key provided does not match the MobWrite Session: ') . $key);
  }
...
?>
tomdavidson’s picture

Actually, it is not an ok work around, for the exit() breaks the share by URL functionality. I think I need to pass the message and maybe a window.location, but what started this was that when the drupal_goto() was hit, the new document load would kill mobwrite.share() window.location would so the same... But if the sync gateway data is not cleared it shouldn't matter. Will take more experimenting to figure it out.

tomdavidson’s picture

Returned the code back to window.location and drupal_gos just to verify the problem. When the js calls back to php that results in drupal_goto() mobwrite.share() stops.
http://drupalcode.org/viewvc/drupal/contributions/modules/mobwrite/mobwr...
http://drupalcode.org/viewvc/drupal/contributions/modules/mobwrite/mobwr...

Going back to $.get() and exit() as showing #6, #5 and #2 - but URL sharing is broken. I liked using dsm() for the status messages, but have the HTML area for mobwrite messages. I think the URL access mode just needs to be rethunk or maybe keep the same but use a different callback....

tomdavidson’s picture

OK, works fine now. This mess is a result of getting mixed up on the crunched time line - I got two callbacks messed up and forgot what I was doing :)
On click of share option, a callback is pinged to set the share mode and get sharing started. For Share by URL, an other callback is used for for URL recipients. I was mixing them up. Now URL recipients run through their own callback. Issue resolved. Kind of. Requires additional editors to click on the correct share option to join the session.

So mobwrite_share_mode() now allso allows a share mode query so in Drupal.Behavoirs mobwriteShareMode() can get the existing mode and initiate the call to mobwrite.share(). Im just about there, but something is off in the JS... http://drupalcode.org/viewvc/drupal/contributions/modules/mobwrite/mobwr...

tomdavidson’s picture

Status: Active » Needs review

The original issue is not resolved. There are still unresolved secondary UI issues that are to address in #886054: MobWrite Status messages do not update. so there can be better focus. As Berdir pointed out the issue lay with mixing the drupal_goto()s and exit()s in the same callback. These different actions were on conditional branches and in my little mind made sense :)

Now, mobwrite_share_mode() uses only exit()s and there is an additional option of 'get' for JS to find out if the share mode is already set or not. And as mentioned above, the two different callbacks are straightened out.