? mark.form_widget.patch
Index: mark.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mark/mark.admin.inc,v
retrieving revision 1.2
diff -u -p -r1.2 mark.admin.inc
--- mark.admin.inc	12 Mar 2010 15:46:50 -0000	1.2
+++ mark.admin.inc	29 Jul 2010 17:50:43 -0000
@@ -136,6 +136,9 @@ function mark_edit_form($form_state, $ma
     '#default_value' => $mark->settings['global'],
     '#description' => t('By default a mark is specific to a particular user. Making a mark global shares the same mark among all users'),
   );
+  if (in_array($mark->basetable, module_invoke_all('mark_type_allowed_settings', 'form_widget'))) {
+    _mark_add_form_widget_settings($form, $mark);
+  }
   $form['new']['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save'),
@@ -143,6 +146,42 @@ function mark_edit_form($form_state, $ma
   return $form;
 }
 
+function _mark_add_form_widget_settings(&$form, $mark) {
+  $form['settings']['form_widget'] = array(
+    '#title' => t('Display in !type form', array('!type' => $mark->basetable)),
+    '#type' => 'checkbox',
+    '#default_value' => $mark->settings['form_widget'],
+    '#description' => t('Adds a checkbox to toggle the mark to the !type form. Especially useful for global marks.', array('!type' => $mark->basetable)),
+  );
+  $form['settings']['form_widget_advanced'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Form Widget Advanced Settings'),
+    '#description' => t('Additional settings to define the behavior of the form widget.'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#tree' => TRUE,
+  );
+  $form['settings']['form_widget_advanced']['show_message'] = array(
+    '#title' => t('Show confirmation text after form submit.'),
+    '#type' => 'checkbox',
+    '#default_value' => $mark->settings['form_widget_advanced']['show_message'],
+  );
+
+  if ($mark->basetable == 'node') {
+    $types = node_get_types('names');
+    $allowed_types = $mark->settings['form_widget_advanced']['allowed_types'];
+    if (!is_array($allowed_types)) {
+      $allowed_types = array($allowed_types);
+    }
+    $form['settings']['form_widget_advanced']['allowed_types'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Allowed types for this Mark'),
+      '#options' => $types,
+      '#default_value' => $allowed_types,
+    );
+  }
+}
+
 /**
  * Submission handler for mark editing.
  */
@@ -246,3 +285,13 @@ function mark_status_form_submit($form, 
   }
   $form_state['redirect'] = 'admin/settings/mark';
 }
+
+/**
+ * Implementation of hook_mark_type_allowed_settings().
+ */
+function mark_mark_type_allowed_settings($setting) {
+  switch ($setting) {
+    case 'form_widget':
+      return array('node', 'comments');
+  }
+}
Index: mark.api.php
===================================================================
RCS file: mark.api.php
diff -N mark.api.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mark.api.php	29 Jul 2010 17:50:43 -0000
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * Implementation of hook_mark_type_allowed_settings().
+ *
+ * @param $setting
+ *  A specific Mark configuration option.
+ *
+ * @return
+ *  An array of Mark types that should offer the configuration option named in $setting.
+ * @see
+ *  mark_edit_form
+ */
+function hook_mark_type_allowed_settings($setting) {
+  switch ($setting) {
+    case 'form_widget':
+      // This is needed in any module that implements form-widget support for User marks or Feeds source marks
+      return array('users', 'feeds_source');
+  }
+}
\ No newline at end of file
Index: mark.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mark/mark.module,v
retrieving revision 1.4
diff -u -p -r1.4 mark.module
--- mark.module	12 Mar 2010 15:46:50 -0000	1.4
+++ mark.module	29 Jul 2010 17:50:43 -0000
@@ -206,6 +206,130 @@ function mark_block($op = 'list', $delta
 }
 
 /**
+ * Implementation of hook_nodeapi().
+ */
+function mark_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
+  switch ($op) {
+    case 'update':
+    case 'insert':
+      // Processes mark voting from the form widget.
+      mark_apply_form_changes($node->mark, 'node', $node->nid);
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_comment().
+ */
+function mark_comment(&$comment, $op) {
+  switch ($op) {
+    case 'update':
+    case 'insert':
+      // Processes mark voting from the form widget.
+      mark_apply_form_changes($comment['mark'], 'comments', $comment['cid']);
+      break;
+  }
+}
+
+function mark_apply_form_changes($marks, $type = 'node', $id = NULL) {
+  if (!isset($id)) {
+    return;
+  }
+  foreach ($marks as $name => $value) {
+    $status = mark_is_set($name, $type, $id);
+    dpm($value); dpm($status);
+    if (($value && !$status) || (!$value && $status)) {
+      $mark = mark_load($name);
+      list ($msg, ) = mark_vote_process($mark, $type, $id);
+      if ($mark->settings['form_widget_advanced']['show_message']) {
+        drupal_set_message($msg);
+      }
+    }
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ */
+function mark_form_alter(&$form, &$form_state, $form_id) {
+  if ($form['#id'] == 'node-form') {
+    mark_add_mark_form($form, 'node', $form['#node']->nid, $form['#node']);
+  }
+  if ($form['#id'] == 'comment-form') {
+    mark_add_mark_form($form, 'comments', $form['cid']['#value'], $form);
+    $form['mark']['#collapsed'] = TRUE;
+  }
+}
+
+/**
+ * Constructs Mark fieldset for object form.
+ *
+ * @param $form
+ *  The form object to which mark is being added.
+ * @param $type
+ *  The type of marks being added.
+ * @param $id
+ *  The content id of the current object.
+ * @param $object
+ *  The object itself, where applicable. Used to allow finer grained form-widget controls per Mark.
+ */
+function mark_add_mark_form(&$form, $type = 'node', $id = NULL, $object = NULL) {
+  $marks = mark_load_form_enabled($type);
+  $elements = array();
+  foreach ($marks as $mark) {
+    if (!_mark_form_widget_allowed($mark, $type, $object)) {
+      continue;
+    }
+    $default_value = isset($id) ? mark_is_set($mark->name, $type, $id) : FALSE;
+    $elements[$mark->name] = array(
+      '#title' => $mark->settings['mark_text'],
+      '#description' => $mark->settings['mark_confirm_text'],
+      '#type' => 'checkbox',
+      '#default_value' => $default_value,
+    );
+  }
+  if (!empty($elements)) {
+    $form['mark'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Marks'),
+      '#access' => user_access('mark items'),
+      '#collapsible' => TRUE,
+      '#tree' => TRUE,
+    );
+    $form['mark'] = array_merge($form['mark'], $elements);
+  }
+}
+
+/**
+ * Check for type-specific configurations that allow or disallow this particular
+ * object to have a mark form widget attached to it.
+ */
+function _mark_form_widget_allowed($mark, $type = 'node', $object) {
+  switch ($type) {
+    case 'node':
+      return !in_array($object->type, $mark->settings['form_widget_advanced']['allowed_types'], TRUE)
+        && !empty($mark->settings['form_widget_advanced']['allowed_types']);    
+  }
+  return TRUE;
+}
+
+/**
+ * Implementation of hook_content_extra_fields().
+ */
+function mark_content_extra_fields($type_name) {
+  $extra = array();
+  $marks = mark_load_form_enabled('node');
+  if (!empty($marks)) {
+    $extra['mark'] = array(
+      'label' => t('Marks'),
+      'description' => t('Marks fieldset.'),
+      'weight' => 0,
+    );
+  }
+  return $extra;
+}
+
+/**
  * Load marks.
  *
  * param $name
@@ -251,6 +375,24 @@ function mark_load($name = NULL, $lookup
 }
 
 /**
+ * Get all marks enabled for a Form widget of a given type.
+ *
+ * @param type
+ *  Optional. The table type. Defaults to 'node'.
+ * @param reset
+ *  Optional. Whether to reset the static cache or not, defaults to false.
+ */
+function mark_load_form_enabled($type = 'node', $reset = FALSE) {
+  $marks = mark_load($type, 'tables', $reset);
+  foreach ($marks as $name => $mark) {
+    if (!$mark->settings['form_widget']) {
+      unset($marks[$name]);
+    }
+  }
+  return $marks;
+}
+
+/**
  * See if a users has set a mark.
  * 
  * param $name
@@ -321,28 +463,7 @@ function mark_vote($mark, $content_type,
   }
   else {
     if (drupal_valid_token($_POST['token'], $content_type .'/'. $content_id)) {
-      $criteria = array(
-        'content_type' => $content_type,
-        'content_id' => $content_id,
-        'value_type' => 'mark',
-        'value' => 1,
-        'tag' => $mark->name,
-      );
-
-      if (mark_is_set($mark->name, $content_type, $content_id)) {
-        if (!$mark->settings['global']) {
-          global $user;
-          $criteria['uid'] = $user->uid;
-        }
-        $votes = array();
-        votingapi_set_votes($votes, $criteria);
-        $msg = $mark->settings['unmark_confirm_text'];
-      }
-      else {
-        $votes = array($criteria);
-        votingapi_set_votes($votes);
-        $msg = $mark->settings['mark_confirm_text'];
-      }
+      list ($msg, $criteria) = mark_vote_process($mark, $content_type, $content_id);
       return drupal_json(array(
         'markup' => theme('mark_link', array($mark->name => array(
           'mark' => $mark,
@@ -356,8 +477,60 @@ function mark_vote($mark, $content_type,
   return drupal_access_denied();
 }
 
+function mark_vote_process($mark, $content_type, $content_id) {
+  $criteria = array(
+    'content_type' => $content_type,
+    'content_id' => $content_id,
+    'value_type' => 'mark',
+    'value' => 1,
+    'tag' => $mark->name,
+  );
+
+  if (mark_is_set($mark->name, $content_type, $content_id)) {
+    if (!$mark->settings['global']) {
+      global $user;
+      $criteria['uid'] = $user->uid;
+    }
+    _mark_vote_off($mark, $criteria);
+    $msg = $mark->settings['unmark_confirm_text'];
+  }
+  else {
+    _mark_vote_on($mark, $criteria);
+    $msg = $mark->settings['mark_confirm_text'];
+  }
+  return array($msg, $criteria);
+}
+
+/**
+ * Toggle a mark on.
+ *
+ * @param $mark
+ *  The mark definition.
+ * @param $criteria
+ *  The details of the object and the mark used by VotingAPI.
+ */
+function _mark_vote_on($mark, $criteria) {
+  $votes = array($criteria);
+  votingapi_set_votes($votes);
+  module_invoke_all('mark_changed', 'on', $mark, $criteria);
+}
+
+/**
+ * Toggle a mark off.
+ *
+ * @param $mark
+ *  The mark definition.
+ * @param $criteria
+ *  The details of the object and the mark used by VotingAPI.
+ */
+function _mark_vote_off($mark, $criteria) {
+  $votes = array();
+  votingapi_set_votes($votes, $criteria);
+  module_invoke_all('mark_changed', 'off', $mark, $criteria);
+}
+
 /**
- * Confirm form for non-ajax fallback.
+ * Confirm form for non-ajax fallback. (As opposed to the form widget.)
  */
 function mark_vote_confirm($form_state, $mark, $content_type, $content_id) {
   $form = array();
