diff --git a/boolean_icon.install b/boolean_icon.install
index c72044e..ac66e4c 100644
--- a/boolean_icon.install
+++ b/boolean_icon.install
@@ -1,9 +1,23 @@
-<?php 
+<?php
+
+/**
+ * @file
+ * Install, uninstall and update hooks for boolean_icon.module.
+ */
 
 /**
  * Implements hook_uninstall().
  */
 function boolean_icon_uninstall() {
   variable_del('boolean_icon_true_ico');
-  variable_del('boolean_icon_false_ico');  
+  variable_del('boolean_icon_false_ico');
+  variable_del('boolean_icon_locked_ico');
+}
+
+/**
+ * Grant permission to admin role.
+ */
+function boolean_icon_update_7001() {
+  menu_rebuild();
+  user_role_grant_permissions(variable_get('user_admin_role', 1), array('boolean_icon one_click'));
 }
\ No newline at end of file
diff --git a/boolean_icon.module b/boolean_icon.module
index 09f9dad..5db95de 100644
--- a/boolean_icon.module
+++ b/boolean_icon.module
@@ -1,4 +1,4 @@
-<?php 
+<?php
 
 
 /**
@@ -26,10 +26,10 @@ function boolean_icon_field_formatter_view($entity_type, $entity, $field, $insta
       foreach ($items as $delta => $item) {
         // Set icon.
         $icon = $item['value'] ? 'yes.png' : 'no.png';
-        $icon = $item['value'] ? 
-          variable_get('boolean_icon_true_ico', drupal_get_path('module', 'boolean_icon') . '/yes.png') : 
+        $icon = $item['value'] ?
+          variable_get('boolean_icon_true_ico', drupal_get_path('module', 'boolean_icon') . '/yes.png') :
           variable_get('boolean_icon_false_ico', drupal_get_path('module', 'boolean_icon') . '/no.png');
-        
+
         // Set image title.
         if (isset($allowed_values[$item['value']])) {
           $title = field_filter_xss($allowed_values[$item['value']]);
@@ -38,7 +38,7 @@ function boolean_icon_field_formatter_view($entity_type, $entity, $field, $insta
           // If no match was found in allowed values, fall back to the key.
           $title = field_filter_xss($item['value']);
         }
-        
+
         // Return element.
         $element[$delta] = array(
           '#theme' => 'image',
@@ -54,6 +54,121 @@ function boolean_icon_field_formatter_view($entity_type, $entity, $field, $insta
 
 
 /**
+ * Implements hook_menu();
+ */
+function boolean_icon_menu() {
+  $items['ajax/boolean-icon/%/%/%'] = array(
+    'title' => 'Publish a node with just one click',
+    'page callback' => 'boolean_icon_click_publish_callback',
+    'page arguments' => array(2, 3, 4),
+    'access arguments' => array('boolean_icon one_click'),
+    'type' => MENU_CALLBACK,
+  );
+
+  return $items;
+}
+
+/**
+ * Publishit callback
+ *
+ * A callback used to publish/unpublish nodes or comments.
+ *
+ * @param
+ *  The node object.
+ */
+function boolean_icon_click_publish_callback($action, $type, $id, $callback_type = 'ajax') {
+  $entity = $type == 'node' ? node_load($id) : comment_load($id);
+
+  if (empty($entity)) {
+    return MENU_ACCESS_DENIED;
+  }
+
+  if ($action != 'publish' && $action != 'unpublish') {
+    return MENU_ACCESS_DENIED;
+  }
+
+  // Check for a token to prevent. Tokens are required because they prevent CSRF,
+  // https://security.drupal.org/node/2429
+  if (empty($_GET['token']) || !drupal_valid_token($_GET['token'], 'ajax/boolean-icon/' . $action . '/' . $type . '/' . $id)) {
+    return MENU_ACCESS_DENIED;
+  }
+
+  // This functionality should be accesed only.
+  // via an ajax call.
+  if ($callback_type != 'ajax') {
+    return MENU_ACCESS_DENIED;
+  }
+
+  // If the node is locked return an error message.
+  if ($type == 'node' && module_exists('content_lock') && content_lock_fetch_lock($entity->nid) != FALSE) {
+
+    $lock = content_lock_fetch_lock($entity->nid);
+    $message = t('The content you tried to un/publish, was locked by %user after this page was refreshed.', array('%user' => check_plain($lock->name)));
+
+    $commands = array();
+    $commands[] = ajax_command_replace('.node-' . $entity->nid . ' .publishit-link', '<span class="marker">' . $message . '</span>');
+    $commands[] = ajax_command_html('.node-' . $entity->nid . ' .publishit-link', t('Locked'));
+
+    ajax_deliver(array('#type' => 'ajax', '#commands' => $commands));
+
+  }
+  // If everything looks OK, publish or unpublish
+  // the node.
+  else {
+
+
+    // Publish if unpublished and vice versa. Also prepare
+    // the new content for the link.
+    if ($action == 'publish') {
+      $new_action = 'unpublish';
+      $link_content = theme('image', array('path' => variable_get('boolean_icon_true_ico', drupal_get_path('module', 'boolean_icon') . '/on.png')));
+
+      $entity->status = 1;
+      entity_save($type, $entity);
+    }
+    elseif ($action == 'unpublish') {
+      $new_action = 'publish';
+      $link_content = theme('image', array('path' => variable_get('boolean_icon_false_ico', drupal_get_path('module', 'boolean_icon') . '/off.png')));
+
+      $entity->status = 0;
+      entity_save($type, $entity);
+    }
+
+    // Generate the token.
+    $token = boolean_icon_token_generate($type, $id, $new_action);
+
+    // Prepare the new link
+    $link = l($link_content, 'ajax/boolean-icon/' . $new_action . '/' . $type . '/' . $id . '/nojs', array(
+        'attributes' => array('class' => 'publishit-link-' . $type . '-' . $id . ' use-ajax'),
+        'query' => array('token' => $token),
+        'html' => TRUE
+      )
+    );
+
+    // Change the link text in the view where this field is displayed.
+    $commands = array();
+    $commands[] = ajax_command_replace('.publishit-link-' . $type . '-' . $id, $link);
+
+    ajax_deliver(array('#type' => 'ajax', '#commands' => $commands));
+
+  }
+
+}
+
+/**
+ * Implements hook_permission();
+ */
+function boolean_icon_permission() {
+  return array(
+    'boolean_icon one_click' => array(
+      'title' => t('Use one-click publish on nodes/comments'),
+      'description' => t('Publish nodes/comments with just one click on views field.'),
+      'restrict access' => TRUE,
+    ),
+  );
+}
+
+/**
  * Implements hook_views_api().
  */
 function boolean_icon_views_api() {
@@ -63,3 +178,12 @@ function boolean_icon_views_api() {
   );
 }
 
+/**
+ * Generate the token.
+ *
+ * Tokens are required because they prevent CSRF,
+ *  https://security.drupal.org/node/2429.
+ */
+function boolean_icon_token_generate($type, $id, $action) {
+  return drupal_get_token('ajax/boolean-icon/' . $action . '/' . $type . '/' . $id);
+}
diff --git a/locked.png b/locked.png
new file mode 100644
index 0000000000000000000000000000000000000000..fe572a496422e4d85642dadbbe8826316303fe2a
GIT binary patch
literal 448
zcmeAS@N?(olHy`uVBq!ia0vp^+(69F!3-o>A0K4`Qq09po*^6@9Je3(KLB!z0(?ST
z|NsC0=NH4TuM9uGGW`0&@be49w>J!5-!goC!*K1|wU3V(K0Ic4bCcoqO@`;^8J=BW
zcy^xQ@o|O+hZySW>Pr0?%KRBh{TRyp7z(@@3cMJy+!!+57?PYAk{lUgY#Bl=82n5a
zJPjB;3>chs7#y@1fYx1|Rv8JjU9BX@FBr%r3>cPIHSPiG;4JWnECzZ@2!t6g-L3lr
z6qG4(jVKAuPb(=;EJ|f?Ovz75RdCBJN-fVX$}U!L4mK^^`q&JpP6VXRxhOTUBr`ux
zAtW<5mBB>cQs2<%_@zIKfb!X%E{-7_GgHra@*OhZak!Wtx>icnabcW6TEnE@@e{Y0
zXwOUeS)H7<c-8GB@8q6;yOzE?ey{7__ob_2EKl^Z7wr(1Y?F9wacc4rlclLM(>+tx
zY~9(L!gX%vqrKA)bqgF?Inn&}&i|1s=dY_{?C0YCFU%+^2(*^L)78&qol`;+0KW#p
ArT_o{

literal 0
HcmV?d00001

diff --git a/views/boolean_icon.views.inc b/views/boolean_icon.views.inc
index a618f0d..8c9f55a 100644
--- a/views/boolean_icon.views.inc
+++ b/views/boolean_icon.views.inc
@@ -1,7 +1,7 @@
-<?php 
+<?php
 
 /**
- * @file 
+ * @file
  *  Views hooks file.
  */
 
diff --git a/views/handlers/boolean_icon_hanlder_field_boolean_graphic.inc b/views/handlers/boolean_icon_hanlder_field_boolean_graphic.inc
index 39b1d51..e8b4c20 100644
--- a/views/handlers/boolean_icon_hanlder_field_boolean_graphic.inc
+++ b/views/handlers/boolean_icon_hanlder_field_boolean_graphic.inc
@@ -1,16 +1,22 @@
 <?php
 
 /**
+ * @file
+ * Field handler for graphic representations of boolean fields.
+ */
+
+/**
  * A handler to provide graphic displays for booleans.
  *
  * Based on: views_handler_field_boolean
- * 
+ *
  * @ingroup views_field_handlers
  */
 class boolean_icon_handler_field_boolean_graphic extends views_handler_field {
   function option_definition() {
     $options = parent::option_definition();
     $options['not'] = array('definition bool' => 'reverse');
+    $options['click_publish'] = array('default' => FALSE);
 
     return $options;
   }
@@ -22,6 +28,14 @@ class boolean_icon_handler_field_boolean_graphic extends views_handler_field {
       '#description' => t('If checked, true will be displayed as false.'),
       '#default_value' => $this->options['not'],
     );
+
+    $form['click_publish'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Add click-publish link'),
+      '#description' => t('Icon will become a clickable link, that will be used to publish/unpublish entites.'),
+      '#default_value' => $this->options['click_publish'],
+    );
+
     parent::options_form($form, $form_state);
   }
 
@@ -31,16 +45,53 @@ class boolean_icon_handler_field_boolean_graphic extends views_handler_field {
       $value = !$value;
     }
 
-    $icon = $value ?
-          variable_get('boolean_icon_true_ico', drupal_get_path('module', 'boolean_icon') . '/yes.png') : 
-          variable_get('boolean_icon_false_ico', drupal_get_path('module', 'boolean_icon') . '/no.png');
-    $title = $value ? t('True') : t('False');
-            
-    // Return element.
-    return array(
-      '#theme' => 'image',
-      '#path' => $icon,
-      '#title' => $title,
-    );
+    if (empty($this->options['click_publish'])) {
+      $icon = $value ?
+            variable_get('boolean_icon_true_ico', drupal_get_path('module', 'boolean_icon') . '/on.png'):
+            variable_get('boolean_icon_false_ico', drupal_get_path('module', 'boolean_icon') . '/off.png');
+      $title = $value ? t('True') : t('False');
+
+      // Return element.
+      return array(
+        '#theme' => 'image',
+        '#path' => $icon,
+        '#title' => $title,
+      );
+    }
+    else {
+      // Get type of entitiy and ID.
+      $type = $this->table;
+      $id = $values->{$this->view->base_field};
+
+      // If the node is locked don't allow the change of status.
+      if ($type == 'node' && module_exists('content_lock') && $values->content_lock_timestamp != NULL) {
+          // Return element.
+          return array(
+            '#theme' => 'image',
+            '#path' => variable_get('boolean_icon_locked_ico', drupal_get_path('module', 'boolean_icon') . '/locked.png'),
+            '#title' => t('Locked'),
+          );
+      }
+      else {
+        // Tokens are required because they prevent CSRF,
+        // https://security.drupal.org/node/2429.
+        $action = $value ? 'unpublish' : 'publish';
+        $token = boolean_icon_token_generate($type, $id, $action);
+        $img = $value ?
+          variable_get('boolean_icon_true_ico', drupal_get_path('module', 'boolean_icon') . '/on.png') :
+          variable_get('boolean_icon_false_ico', drupal_get_path('module', 'boolean_icon') . '/off.png');
+
+        return  array(
+          '#theme' => 'link',
+          '#text' => theme('image', array('path' => $img)),
+          '#path' => 'ajax/boolean-icon/' . $action . '/' . $type . '/' . $id . '/nojs',
+          '#options' => array(
+            'attributes' => array('class' => 'publishit-link-' . $type . '-' . $id . ' use-ajax'),
+            'query' => array('token' => $token),
+            'html' => TRUE,
+          ),
+        );
+      }
+    }
   }
 }
