Last active
February 22, 2017 00:38
-
-
Save jbickar/1849c3debfcfd04034a5bfd5e6b06598 to your computer and use it in GitHub Desktop.
Diff of views_bulk_operations between 7.x-3.3 and 7.x-3.4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/actions/archive.action.inc b/actions/archive.action.inc | |
index f005527..ef36acd 100644 | |
--- a/actions/archive.action.inc | |
+++ b/actions/archive.action.inc | |
@@ -3,10 +3,14 @@ | |
/** | |
* @file | |
* Provides an action for creating a zip archive of selected files. | |
+ * | |
* An entry in the {file_managed} table is created for the newly created archive, | |
* and it is marked as permanent or temporary based on the operation settings. | |
*/ | |
+/** | |
+ * Implements hook_action_info(). | |
+ */ | |
function views_bulk_operations_archive_action_info() { | |
$actions = array(); | |
if (function_exists('zip_open')) { | |
@@ -71,6 +75,10 @@ function views_bulk_operations_archive_action($file, $context) { | |
$archive_file->filemime = file_get_mimetype($destination); | |
$archive_file->uid = $user->uid; | |
$archive_file->status = $context['settings']['temporary'] ? FALSE : FILE_STATUS_PERMANENT; | |
+ // Clear filesize() cache to avoid private file system differences in | |
+ // filesize. | |
+ // @see https://www.drupal.org/node/2743999 | |
+ clearstatcache(); | |
file_save($archive_file); | |
$url = file_create_url($archive_file->uri); | |
@@ -100,8 +108,11 @@ function views_bulk_operations_archive_action_form($context) { | |
} | |
/** | |
- * Assembles a sanitized and unique URI for the archive, and returns it for | |
- * usage by the action callback (views_bulk_operations_archive_action). | |
+ * Assembles a sanitized and unique URI for the archive. | |
+ * | |
+ * @returns array | |
+ * A URI array used by the action callback | |
+ * (views_bulk_operations_archive_action). | |
*/ | |
function views_bulk_operations_archive_action_submit($form, $form_state) { | |
// Validate the scheme, fallback to public if it's somehow invalid. | |
@@ -156,10 +167,12 @@ function views_bulk_operations_archive_action_views_bulk_operations_form($option | |
/** | |
* Create a sanitized and unique version of the provided filename. | |
* | |
- * @param $filename | |
- * String filename | |
+ * @param string $filename | |
+ * The filename to create. | |
+ * @param array $archive_list | |
+ * The list of files already in the archive. | |
* | |
- * @return | |
+ * @return string | |
* The new filename. | |
*/ | |
function _views_bulk_operations_archive_action_create_filename($filename, $archive_list) { | |
@@ -167,7 +180,7 @@ function _views_bulk_operations_archive_action_create_filename($filename, $archi | |
// some filesystems, not many applications handle them well. | |
$filename = preg_replace('/[\x00-\x1F]/u', '_', $filename); | |
if (substr(PHP_OS, 0, 3) == 'WIN') { | |
- // These characters are not allowed in Windows filenames | |
+ // These characters are not allowed in Windows filenames. | |
$filename = str_replace(array(':', '*', '?', '"', '<', '>', '|'), '_', $filename); | |
} | |
diff --git a/actions/change_owner.action.inc b/actions/change_owner.action.inc | |
new file mode 100644 | |
index 0000000..697670d | |
--- /dev/null | |
+++ b/actions/change_owner.action.inc | |
@@ -0,0 +1,65 @@ | |
+<?php | |
+ | |
+/** | |
+ * @file | |
+ * Implements a generic entity change owner action. | |
+ */ | |
+ | |
+/** | |
+ * Implements hook_action_info(). | |
+ */ | |
+function views_bulk_operations_change_owner_action_info() { | |
+ return array( | |
+ 'views_bulk_operations_change_owner_action' => array( | |
+ 'type' => 'entity', | |
+ 'label' => t('Change owner'), | |
+ 'configurable' => TRUE, | |
+ 'behavior' => array('changes_property'), | |
+ 'triggers' => array('any'), | |
+ ), | |
+ ); | |
+} | |
+ | |
+/** | |
+ * Action function. | |
+ */ | |
+function views_bulk_operations_change_owner_action($entity, $context) { | |
+ $entity->uid = $context['owner_uid']; | |
+} | |
+ | |
+/** | |
+ * Action form function. | |
+ */ | |
+function views_bulk_operations_change_owner_action_form($context, &$form_state) { | |
+ $form['owner_username'] = array( | |
+ '#type' => 'textfield', | |
+ '#maxlength' => USERNAME_MAX_LENGTH, | |
+ '#title' => t('Owner'), | |
+ '#required' => TRUE, | |
+ '#description' => t('Choose the user you would like to set as the owner.'), | |
+ '#autocomplete_path' => 'user/autocomplete', | |
+ ); | |
+ | |
+ return $form; | |
+} | |
+ | |
+/** | |
+ * Action form validate function. | |
+ * | |
+ * Checks that the submitted text is a valid username. | |
+ */ | |
+function views_bulk_operations_change_owner_action_validate($form, $form_state) { | |
+ if (!user_load_by_name($form_state['values']['owner_username'])) { | |
+ form_set_error('owner_username', t('Valid username required.')); | |
+ } | |
+} | |
+ | |
+/** | |
+ * Action form submit function. | |
+ * | |
+ * Pass submitted username back to views_bulk_operations_change_owner. | |
+ */ | |
+function views_bulk_operations_change_owner_action_submit($form, $form_state) { | |
+ $user = user_load_by_name($form_state['values']['owner_username']); | |
+ return array('owner_uid' => $user->uid); | |
+} | |
diff --git a/actions/delete.action.inc b/actions/delete.action.inc | |
index 52c72d2..439a504 100644 | |
--- a/actions/delete.action.inc | |
+++ b/actions/delete.action.inc | |
@@ -24,11 +24,46 @@ function views_bulk_operations_delete_action_info() { | |
); | |
} | |
+function views_bulk_operations_delete_item_views_bulk_operations_form($settings) { | |
+ $form = array(); | |
+ $form['log'] = array( | |
+ '#type' => 'checkbox', | |
+ '#title' => t('Log individual deletions'), | |
+ '#description' => t('Note: Deleting large amounts of entities will generate large amounts of log messages.'), | |
+ '#default_value' => !empty($settings['log']), | |
+ ); | |
+ | |
+ return $form; | |
+} | |
+ | |
function views_bulk_operations_delete_item($entity, $context) { | |
$info = entity_get_info($context['entity_type']); | |
$entity_id = $entity->{$info['entity keys']['id']}; | |
entity_delete($context['entity_type'], $entity_id); | |
+ | |
+ // Add a message to the watchdog if we've been configured to do so. | |
+ if (!empty($context['settings']['log'])) { | |
+ // Log an appropriate message for this entity type, using the format from | |
+ // the node, taxonomy and user module for their entity types. | |
+ switch ($context['entity_type']) { | |
+ case 'node': | |
+ watchdog('content', '@type: deleted %title.', array('@type' => $entity->type, '%title' => $entity->title)); | |
+ break; | |
+ | |
+ case 'taxonomy_term': | |
+ watchdog('taxonomy', 'Deleted term %name.', array('%name' => $entity->name), WATCHDOG_NOTICE); | |
+ break; | |
+ | |
+ case 'user': | |
+ watchdog('user', 'Deleted user: %name %email.', array('%name' => $entity->name, '%email' => '<' . $entity->mail . '>'), WATCHDOG_NOTICE); | |
+ break; | |
+ | |
+ default: | |
+ watchdog('entity', 'Deleted @type %label.', array('@type' => $context['entity_type'], '%label' => entity_label($context['entity_type'], $entity))); | |
+ break; | |
+ } | |
+ } | |
} | |
function views_bulk_operations_delete_revision($entity, $context) { | |
diff --git a/actions/modify.action.inc b/actions/modify.action.inc | |
index 301b17b..06fa46d 100644 | |
--- a/actions/modify.action.inc | |
+++ b/actions/modify.action.inc | |
@@ -1,24 +1,30 @@ | |
<?php | |
/** | |
- * @file VBO action to modify entity values (properties and fields). | |
+ * @file | |
+ * VBO action to modify entity values (properties and fields). | |
*/ | |
// Specifies that all available values should be shown to the user for editing. | |
define('VBO_MODIFY_ACTION_ALL', '_all_'); | |
+/** | |
+ * Implements hook_action_info(). | |
+ */ | |
function views_bulk_operations_modify_action_info() { | |
- return array('views_bulk_operations_modify_action' => array( | |
- 'type' => 'entity', | |
- 'label' => t('Modify entity values'), | |
- 'behavior' => array('changes_property'), | |
- // This action only works when invoked through VBO. That's why it's | |
- // declared as non-configurable to prevent it from being shown in the | |
- // "Create an advanced action" dropdown on admin/config/system/actions. | |
- 'configurable' => FALSE, | |
- 'vbo_configurable' => TRUE, | |
- 'triggers' => array('any'), | |
- )); | |
+ return array( | |
+ 'views_bulk_operations_modify_action' => array( | |
+ 'type' => 'entity', | |
+ 'label' => t('Modify entity values'), | |
+ 'behavior' => array('changes_property'), | |
+ // This action only works when invoked through VBO. That's why it's | |
+ // declared as non-configurable to prevent it from being shown in the | |
+ // "Create an advanced action" dropdown on admin/config/system/actions. | |
+ 'configurable' => FALSE, | |
+ 'vbo_configurable' => TRUE, | |
+ 'triggers' => array('any'), | |
+ ), | |
+ ); | |
} | |
/** | |
@@ -28,7 +34,7 @@ function views_bulk_operations_modify_action_info() { | |
* replacing the existing values, or appending to them (based on user input). | |
*/ | |
function views_bulk_operations_modify_action($entity, $context) { | |
- list(,,$bundle_name) = entity_extract_ids($context['entity_type'], $entity); | |
+ list(,, $bundle_name) = entity_extract_ids($context['entity_type'], $entity); | |
// Handle Field API fields. | |
if (!empty($context['selected']['bundle_' . $bundle_name])) { | |
// The pseudo entity is cloned so that changes to it don't get carried | |
@@ -38,7 +44,7 @@ function views_bulk_operations_modify_action($entity, $context) { | |
// Get this field's language. We can just pull it from the pseudo entity | |
// as it was created using field_attach_form and entity_language so it's | |
// already been figured out if this field is translatable or not and | |
- // applied the appropriate language code to the field | |
+ // applied the appropriate language code to the field. | |
$language = key($pseudo_entity->{$key}); | |
// Replace any tokens that might exist in the field columns. | |
foreach ($pseudo_entity->{$key}[$language] as $delta => &$item) { | |
@@ -58,9 +64,11 @@ function views_bulk_operations_modify_action($entity, $context) { | |
if ($field_info['cardinality'] != FIELD_CARDINALITY_UNLIMITED && $field_count > $field_info['cardinality']) { | |
$entity_label = entity_label($context['entity_type'], $entity); | |
$warning = t('Tried to set !field_count values for field !field_name that supports a maximum of !cardinality.', | |
- array('!field_count' => $field_count, | |
- '!field_name' => $field_info['field_name'], | |
- '!cardinality' => $field_info['cardinality'])); | |
+ array( | |
+ '!field_count' => $field_count, | |
+ '!field_name' => $field_info['field_name'], | |
+ '!cardinality' => $field_info['cardinality'], | |
+ )); | |
drupal_set_message($warning, 'warning', FALSE); | |
} | |
@@ -76,11 +84,17 @@ function views_bulk_operations_modify_action($entity, $context) { | |
} | |
// Handle properties. | |
+ // Use the wrapper to set property values, since some properties need | |
+ // additional massaging by their setter callbacks. | |
+ // The wrapper will automatically modify $entity itself. | |
+ $wrapper = entity_metadata_wrapper($context['entity_type'], $entity); | |
+ // The default setting for 'revision' property (create new revisions) should | |
+ // be respected for nodes. This requires some special treatment. | |
+ if ($context['entity_type'] == 'node' && in_array('revision', variable_get('node_options_' . $bundle_name)) && !in_array('revision', $context['selected']['properties'])) { | |
+ $wrapper->revision->set(1); | |
+ } | |
+ | |
if (!empty($context['selected']['properties'])) { | |
- // Use the wrapper to set property values, since some properties need | |
- // additional massaging by their setter callbacks. | |
- // The wrapper will automatically modify $entity itself. | |
- $wrapper = entity_metadata_wrapper($context['entity_type'], $entity); | |
foreach ($context['selected']['properties'] as $key) { | |
if (!$wrapper->$key->access('update')) { | |
// No access. | |
@@ -113,7 +127,8 @@ function views_bulk_operations_modify_action($entity, $context) { | |
* entity bundle, as provided by field_attach_form(). | |
*/ | |
function views_bulk_operations_modify_action_form($context, &$form_state) { | |
- // This action form uses admin-provided settings. If they were not set, pull the defaults now. | |
+ // This action form uses admin-provided settings. If they were not set, pull | |
+ // the defaults now. | |
if (!isset($context['settings'])) { | |
$context['settings'] = views_bulk_operations_modify_action_views_bulk_operations_form_options(); | |
} | |
@@ -126,7 +141,8 @@ function views_bulk_operations_modify_action_form($context, &$form_state) { | |
// and filled with form data. | |
// After submit, the pseudo-entities get passed to the actual action | |
// (views_bulk_operations_modify_action()) which copies the data from the | |
- // relevant pseudo-entity constructed here to the actual entity being modified. | |
+ // relevant pseudo-entity constructed here to the actual entity being | |
+ // modified. | |
$form_state['entities'] = array(); | |
$info = entity_get_info($entity_type); | |
@@ -151,7 +167,16 @@ function views_bulk_operations_modify_action_form($context, &$form_state) { | |
'#title' => $property['label'], | |
); | |
- $determined_type = ($property['type'] == 'boolean') ? 'checkbox' : 'textfield'; | |
+ // According to _views_bulk_operations_modify_action_get_properties | |
+ // we have fixed list of supported types. Most of these types are string | |
+ // and only some of them has options list. | |
+ if (isset($property['options list'])) { | |
+ $determined_type = ($property['type'] == 'list') ? 'checkboxes' : 'select'; | |
+ } | |
+ else { | |
+ $determined_type = ($property['type'] == 'boolean') ? 'checkbox' : 'textfield'; | |
+ } | |
+ | |
$form['properties'][$key] = array( | |
'#type' => $determined_type, | |
'#title' => $property['label'], | |
@@ -189,7 +214,7 @@ function views_bulk_operations_modify_action_form($context, &$form_state) { | |
} | |
} | |
- // Going to need this for multilingual nodes | |
+ // Going to need this for multilingual nodes. | |
global $language; | |
foreach ($bundles as $bundle_name => $bundle) { | |
$bundle_key = $info['entity keys']['bundle']; | |
@@ -202,8 +227,8 @@ function views_bulk_operations_modify_action_form($context, &$form_state) { | |
$entity = entity_create($context['entity_type'], $default_values); | |
$form_state['entities'][$bundle_name] = $entity; | |
- // Show the more detailed label only if the entity type has multiple bundles. | |
- // Otherwise, it would just be confusing. | |
+ // Show the more detailed label only if the entity type has multiple | |
+ // bundles. Otherwise, it would just be confusing. | |
if (count($info['bundles']) > 1) { | |
$label = t('Fields for @bundle_key @label', array('@bundle_key' => $bundle_key, '@label' => $bundle['label'])); | |
} | |
@@ -417,9 +442,9 @@ function views_bulk_operations_modify_action_submit($form, $form_state) { | |
* Properties that can't be changed are entity keys, timestamps, and the ones | |
* without a setter callback. | |
* | |
- * @param $entity_type | |
+ * @param string $entity_type | |
* The entity type whose properties will be fetched. | |
- * @param $display_values | |
+ * @param array $display_values | |
* An optional, admin-provided list of properties and fields that should be | |
* displayed for editing, used to filter the returned list of properties. | |
*/ | |
@@ -435,8 +460,17 @@ function _views_bulk_operations_modify_action_get_properties($entity_type, $disp | |
} | |
} | |
// List of supported types. | |
- $supported_types = array('text', 'token', 'integer', 'decimal', 'date', 'duration', | |
- 'boolean', 'uri', 'list'); | |
+ $supported_types = array( | |
+ 'text', | |
+ 'token', | |
+ 'integer', | |
+ 'decimal', | |
+ 'date', | |
+ 'duration', | |
+ 'boolean', | |
+ 'uri', | |
+ 'list', | |
+ ); | |
$property_info = entity_get_property_info($entity_type); | |
if (empty($property_info['properties'])) { | |
// Stop here if no properties were found. | |
@@ -484,9 +518,9 @@ function _views_bulk_operations_modify_action_get_properties($entity_type, $disp | |
* (through the action settings) then only bundles that have at least one field | |
* selected are returned. | |
* | |
- * @param $entity_type | |
+ * @param string $entity_type | |
* The entity type whose bundles will be fetched. | |
- * @param $context | |
+ * @param array $context | |
* The VBO context variable. | |
*/ | |
function _views_bulk_operations_modify_action_get_bundles($entity_type, $context) { | |
@@ -594,8 +628,8 @@ function views_bulk_operations_modify_action_views_bulk_operations_form($options | |
} | |
foreach ($info['bundles'] as $bundle_name => $bundle) { | |
$bundle_key = $info['entity keys']['bundle']; | |
- // Show the more detailed label only if the entity type has multiple bundles. | |
- // Otherwise, it would just be confusing. | |
+ // Show the more detailed label only if the entity type has multiple | |
+ // bundles. Otherwise, it would just be confusing. | |
if (count($info['bundles']) > 1) { | |
$label = t('Fields for @bundle_key @label', array('@bundle_key' => $bundle_key, '@label' => $bundle['label'])); | |
} | |
diff --git a/actions/user_cancel.action.inc b/actions/user_cancel.action.inc | |
index 147d292..3637e39 100644 | |
--- a/actions/user_cancel.action.inc | |
+++ b/actions/user_cancel.action.inc | |
@@ -1,17 +1,19 @@ | |
<?php | |
/** | |
- * @file | |
- * VBO action to cancel user accounts. | |
- */ | |
+ * @file | |
+ * VBO action to cancel user accounts. | |
+ */ | |
function views_bulk_operations_user_cancel_action_info() { | |
- return array('views_bulk_operations_user_cancel_action' => array( | |
- 'type' => 'user', | |
- 'label' => t('Cancel user account'), | |
- 'configurable' => TRUE, | |
- 'behavior' => array('deletes_property'), | |
- 'triggers' => array('any'), | |
- )); | |
+ return array( | |
+ 'views_bulk_operations_user_cancel_action' => array( | |
+ 'type' => 'user', | |
+ 'label' => t('Cancel user account'), | |
+ 'configurable' => TRUE, | |
+ 'behavior' => array('deletes_property'), | |
+ 'triggers' => array('any'), | |
+ ), | |
+ ); | |
} | |
function views_bulk_operations_user_cancel_action_form($context) { | |
@@ -75,7 +77,17 @@ function views_bulk_operations_user_cancel_action($account, $context) { | |
if (!empty($context['user_cancel_notify'])) { | |
_user_mail_notify('status_canceled', $account); | |
} | |
- user_delete($account->uid); | |
+ // In cases when nodes are to be reassigned to UID 0, the user_delete must | |
+ // not run until *after* the user_cancel has been invoked, otherwise the | |
+ // nodes are deleted before they can be reassigned. Adding the user delete | |
+ // to the batch queue ensures things happen in the correct sequence. | |
+ $batch = array( | |
+ 'operations' => array( | |
+ array('user_delete', array($account->uid)), | |
+ ), | |
+ 'file' => drupal_get_path('module', 'node') . '/node.admin.inc', | |
+ ); | |
+ batch_set($batch); | |
watchdog('user', 'Deleted user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE); | |
break; | |
} | |
diff --git a/css/views_bulk_operations.css b/css/views_bulk_operations.css | |
index a93cf22..d26da62 100644 | |
--- a/css/views_bulk_operations.css | |
+++ b/css/views_bulk_operations.css | |
@@ -1,4 +1,5 @@ | |
-.vbo-select-all-markup, .vbo-table-select-all-markup { | |
+.vbo-select-all-markup, | |
+.vbo-table-select-all-markup { | |
display: none; | |
} | |
@@ -15,9 +16,10 @@ | |
.views-table-row-select-all td { | |
text-align: center; | |
} | |
-.vbo-table-select-all-pages, .vbo-table-select-this-page { | |
- margin: 0 !important; | |
- padding: 2px 5px !important; | |
+.vbo-views-form .vbo-table-select-all-pages, | |
+.vbo-views-form .vbo-table-select-this-page { | |
+ margin: 0; | |
+ padding: 2px 5px; | |
} | |
/* Generic "select all" */ | |
@@ -30,6 +32,6 @@ | |
margin-bottom: 0; | |
} | |
.vbo-fieldset-select-all div { | |
- padding: 0 !important; | |
- margin: 0 !important; | |
+ padding: 0; | |
+ margin: 0; | |
} | |
diff --git a/js/views_bulk_operations.js b/js/views_bulk_operations.js | |
index ca76df8..a4e8237 100644 | |
--- a/js/views_bulk_operations.js | |
+++ b/js/views_bulk_operations.js | |
@@ -1,9 +1,17 @@ | |
(function ($) { | |
+ // Polyfill for jQuery less than 1.6. | |
+ if (typeof $.fn.prop != 'function') { | |
+ jQuery.fn.extend({ | |
+ prop: jQuery.fn.attr | |
+ }); | |
+ } | |
+ | |
Drupal.behaviors.vbo = { | |
attach: function(context) { | |
$('.vbo-views-form', context).each(function() { | |
Drupal.vbo.initTableBehaviors(this); | |
Drupal.vbo.initGenericBehaviors(this); | |
+ Drupal.vbo.toggleButtonsState(this); | |
}); | |
} | |
} | |
@@ -32,7 +40,8 @@ | |
// This is the "select all" checkbox in (each) table header. | |
$('.vbo-table-select-all', form).click(function() { | |
var table = $(this).closest('table')[0]; | |
- $('input[id^="edit-views-bulk-operations"]:not(:disabled)', table).attr('checked', this.checked); | |
+ $('input[id^="edit-views-bulk-operations"]:not(:disabled)', table).prop('checked', this.checked); | |
+ Drupal.vbo.toggleButtonsState(form); | |
// Toggle the visibility of the "select all" row (if any). | |
if (this.checked) { | |
@@ -83,35 +92,43 @@ | |
$('.vbo-select-all-markup', form).show(); | |
$('.vbo-select-this-page', form).click(function() { | |
- $('input[id^="edit-views-bulk-operations"]', form).attr('checked', this.checked); | |
- $('.vbo-select-all-pages', form).attr('checked', false); | |
+ $('input[id^="edit-views-bulk-operations"]', form).prop('checked', this.checked); | |
+ Drupal.vbo.toggleButtonsState(form); | |
+ $('.vbo-select-all-pages', form).prop('checked', false); | |
// Toggle the "select all" checkbox in grouped tables (if any). | |
- $('.vbo-table-select-all', form).attr('checked', this.checked); | |
+ $('.vbo-table-select-all', form).prop('checked', this.checked); | |
}); | |
$('.vbo-select-all-pages', form).click(function() { | |
- $('input[id^="edit-views-bulk-operations"]', form).attr('checked', this.checked); | |
- $('.vbo-select-this-page', form).attr('checked', false); | |
+ $('input[id^="edit-views-bulk-operations"]', form).prop('checked', this.checked); | |
+ Drupal.vbo.toggleButtonsState(form); | |
+ $('.vbo-select-this-page', form).prop('checked', false); | |
// Toggle the "select all" checkbox in grouped tables (if any). | |
- $('.vbo-table-select-all', form).attr('checked', this.checked); | |
+ $('.vbo-table-select-all', form).prop('checked', this.checked); | |
// Modify the value of the hidden form field. | |
$('.select-all-rows', form).val(this.checked); | |
}); | |
+ // Toggle submit buttons' "disabled" states with the state of the operation | |
+ // selectbox. | |
+ $('select[name="operation"]', form).change(function () { | |
+ Drupal.vbo.toggleButtonsState(form); | |
+ }); | |
+ | |
$('.vbo-select', form).click(function() { | |
// If a checkbox was deselected, uncheck any "select all" checkboxes. | |
if (!this.checked) { | |
- $('.vbo-select-this-page', form).attr('checked', false); | |
- $('.vbo-select-all-pages', form).attr('checked', false); | |
+ $('.vbo-select-this-page', form).prop('checked', false); | |
+ $('.vbo-select-all-pages', form).prop('checked', false); | |
// Modify the value of the hidden form field. | |
$('.select-all-rows', form).val('0') | |
var table = $(this).closest('table')[0]; | |
if (table) { | |
// Uncheck the "select all" checkbox in the table header. | |
- $('.vbo-table-select-all', table).attr('checked', false); | |
+ $('.vbo-table-select-all', table).prop('checked', false); | |
// If there's a "select all" row, hide it. | |
if ($('.vbo-table-select-this-page', table).length) { | |
@@ -121,7 +138,24 @@ | |
} | |
} | |
} | |
+ | |
+ Drupal.vbo.toggleButtonsState(form); | |
}); | |
} | |
+ Drupal.vbo.toggleButtonsState = function(form) { | |
+ // If no rows are checked, disable any form submit actions. | |
+ var selectbox = $('select[name="operation"]', form); | |
+ var checkedCheckboxes = $('.vbo-select:checked', form); | |
+ var buttons = $('[id^="edit-select"] input[type="submit"]', form); | |
+ | |
+ if (selectbox.length) { | |
+ var has_selection = checkedCheckboxes.length && selectbox.val() !== '0'; | |
+ buttons.prop('disabled', !has_selection); | |
+ } | |
+ else { | |
+ buttons.prop('disabled', !checkedCheckboxes.length); | |
+ } | |
+ }; | |
+ | |
})(jQuery); | |
diff --git a/views/views_bulk_operations.views.inc b/views/views_bulk_operations.views.inc | |
index 1c7078a..e6c685a 100644 | |
--- a/views/views_bulk_operations.views.inc | |
+++ b/views/views_bulk_operations.views.inc | |
@@ -6,7 +6,8 @@ | |
function views_bulk_operations_views_data_alter(&$data) { | |
foreach (entity_get_info() as $entity_type => $info) { | |
if (isset($info['base table']) && isset($data[$info['base table']]['table'])) { | |
- $data[$info['base table']]['views_bulk_operations'] = array( | |
+ $data[$info['base table']]['views_bulk_operations']['moved to'] = array('views_entity_' . $entity_type, 'views_bulk_operations'); | |
+ $data['views_entity_' . $entity_type]['views_bulk_operations'] = array( | |
'title' => $data[$info['base table']]['table']['group'], | |
'group' => t('Bulk operations'), | |
'help' => t('Provide a checkbox to select the row for bulk operations.'), | |
diff --git a/views/views_bulk_operations_handler_field_operations.inc b/views/views_bulk_operations_handler_field_operations.inc | |
index 61886d4..dcfd534 100644 | |
--- a/views/views_bulk_operations_handler_field_operations.inc | |
+++ b/views/views_bulk_operations_handler_field_operations.inc | |
@@ -6,7 +6,7 @@ | |
* Implements the Views Form API. | |
*/ | |
-class views_bulk_operations_handler_field_operations extends views_handler_field { | |
+class views_bulk_operations_handler_field_operations extends views_handler_field_entity { | |
var $revision = FALSE; | |
function init(&$view, &$options) { | |
@@ -46,6 +46,12 @@ class views_bulk_operations_handler_field_operations extends views_handler_field | |
unset($operation_options['use_queue']); | |
} | |
} | |
+ | |
+ // Check whether this is a revision. | |
+ $table_data = views_fetch_data($this->table); | |
+ if (!empty($table_data['table']['revision'])) { | |
+ $this->revision = TRUE; | |
+ } | |
} | |
function option_definition() { | |
@@ -186,6 +192,14 @@ class views_bulk_operations_handler_field_operations extends views_handler_field | |
$dom_id . '-selected' => array(1), | |
), | |
); | |
+ $form['vbo_operations'][$operation_id]['skip_permission_check'] = array( | |
+ '#type' => 'checkbox', | |
+ '#title' => t('Skip permission step'), | |
+ '#default_value' => !empty($operation_options['skip_permission_check']), | |
+ '#dependency' => array( | |
+ $dom_id . '-selected' => array(1), | |
+ ), | |
+ ); | |
$form['vbo_operations'][$operation_id] += $operation->adminOptionsForm($dom_id, $this); | |
} | |
@@ -263,19 +277,20 @@ class views_bulk_operations_handler_field_operations extends views_handler_field | |
// At this point, the query has already been run, so we can access the results | |
// in order to get the base key value (for example, nid for nodes). | |
foreach ($this->view->result as $row_index => $row) { | |
- $entity_id = $this->get_value($row); | |
+ $this->view->row_index = $row_index; | |
+ $id = $this->get_value($row, $this->real_field); | |
if ($this->options['vbo_settings']['force_single']) { | |
$form[$this->options['id']][$row_index] = array( | |
'#type' => 'radio', | |
'#parents' => array($this->options['id']), | |
- '#return_value' => $entity_id, | |
+ '#return_value' => $id, | |
); | |
} | |
else { | |
$form[$this->options['id']][$row_index] = array( | |
'#type' => 'checkbox', | |
- '#return_value' => $entity_id, | |
+ '#return_value' => $id, | |
'#default_value' => FALSE, | |
'#attributes' => array('class' => array('vbo-select')), | |
); | |
@@ -293,9 +308,12 @@ class views_bulk_operations_handler_field_operations extends views_handler_field | |
if (empty($options['selected'])) { | |
continue; | |
} | |
- | |
$operation = views_bulk_operations_get_operation($operation_id, $entity_type, $options); | |
- if (!$operation || !$operation->access($user)) { | |
+ if (!$operation) { | |
+ continue; | |
+ } | |
+ $skip_permission_check = $operation->getAdminOption('skip_permission_check', FALSE); | |
+ if (!$operation->access($user) && !$skip_permission_check) { | |
continue; | |
} | |
$selected[$operation_id] = $operation; | |
@@ -318,29 +336,7 @@ class views_bulk_operations_handler_field_operations extends views_handler_field | |
* the entity type that VBO is operating on. | |
*/ | |
public function get_entity_type() { | |
- $base_table = $this->view->base_table; | |
- | |
- // If the current field is under a relationship you can't be sure that the | |
- // base table of the view is the base table of the current field. | |
- // For example a field from a node author on a node view does have users as base table. | |
- if (!empty($this->options['relationship']) && $this->options['relationship'] != 'none') { | |
- $relationships = $this->view->display_handler->get_option('relationships'); | |
- $options = $relationships[$this->options['relationship']]; | |
- $data = views_fetch_data($options['table']); | |
- $base_table = $data[$options['field']]['relationship']['base']; | |
- } | |
- // The base table is now known, use it to determine the entity type. | |
- foreach (entity_get_info() as $entity_type => $info) { | |
- if (isset($info['base table']) && $info['base table'] == $base_table) { | |
- return $entity_type; | |
- } | |
- elseif (isset($info['revision table']) && $info['revision table'] == $base_table) { | |
- $this->revision = TRUE; | |
- return $entity_type; | |
- } | |
- } | |
- // This should never happen. | |
- _views_bulk_operations_report_error("Could not determine the entity type for VBO field on views base table %table", array('%table' => $base_table)); | |
- return FALSE; | |
+ return $this->entity_type; | |
} | |
+ | |
} | |
diff --git a/views_bulk_operations.drush.inc b/views_bulk_operations.drush.inc | |
index 09c4fb6..e9ca192 100644 | |
--- a/views_bulk_operations.drush.inc | |
+++ b/views_bulk_operations.drush.inc | |
@@ -154,7 +154,7 @@ function views_bulk_operations_drush_execute($vid = NULL, $operation_id = NULL) | |
$current = 1; | |
foreach ($view->result as $row_index => $result) { | |
$rows[$row_index] = array( | |
- 'entity_id' => $vbo->get_value($result), | |
+ 'entity_id' => $result->{$vbo->real_field}, | |
'views_row' => array(), | |
'position' => array( | |
'current' => $current++, | |
diff --git a/views_bulk_operations.info b/views_bulk_operations.info | |
index 957ca64..040366e 100644 | |
--- a/views_bulk_operations.info | |
+++ b/views_bulk_operations.info | |
@@ -1,7 +1,7 @@ | |
name = Views Bulk Operations | |
description = Provides a way of selecting multiple rows and applying operations to them. | |
dependencies[] = entity | |
-dependencies[] = views | |
+dependencies[] = views (>=3.12) | |
package = Views | |
core = 7.x | |
php = 5.2.9 | |
diff --git a/views_bulk_operations.module b/views_bulk_operations.module | |
index e74eeb1..9b17c44 100644 | |
--- a/views_bulk_operations.module | |
+++ b/views_bulk_operations.module | |
@@ -45,6 +45,7 @@ function views_bulk_operations_load_action_includes() { | |
'archive.action', | |
'argument_selector.action', | |
'book.action', | |
+ 'change_owner.action', | |
'delete.action', | |
'modify.action', | |
'script.action', | |
@@ -75,7 +76,7 @@ function views_bulk_operations_load_action_includes() { | |
*/ | |
function views_bulk_operations_cron() { | |
db_delete('queue') | |
- ->condition('name', db_like('views_bulk_operations_active_queue_'), 'LIKE') | |
+ ->condition('name', db_like('views_bulk_operations_active_queue_') . '%', 'LIKE') | |
->condition('created', REQUEST_TIME - 86400, '<') | |
->execute(); | |
} | |
@@ -214,7 +215,12 @@ function views_bulk_operations_get_operation_info($operation_id = NULL) { | |
function views_bulk_operations_get_operation($operation_id, $entity_type, $options) { | |
$operations = &drupal_static(__FUNCTION__); | |
- if (!isset($operations[$operation_id])) { | |
+ // Create a unique hash of the options. | |
+ $cid = md5(serialize($options)); | |
+ | |
+ // See if there's a cached copy of the operation, including entity type and | |
+ // options. | |
+ if (!isset($operations[$operation_id][$entity_type][$cid])) { | |
// Intentionally not using views_bulk_operations_get_operation_info() here | |
// since it's an expensive function that loads all the operations on the | |
// system, despite the fact that we might only need a few. | |
@@ -223,14 +229,14 @@ function views_bulk_operations_get_operation($operation_id, $entity_type, $optio | |
$operation_info = $plugin['list callback']($operation_id); | |
if ($operation_info) { | |
- $operations[$operation_id] = new $plugin['handler']['class']($operation_id, $entity_type, $operation_info, $options); | |
+ $operations[$operation_id][$entity_type][$cid] = new $plugin['handler']['class']($operation_id, $entity_type, $operation_info, $options); | |
} | |
else { | |
- $operations[$operation_id] = FALSE; | |
+ $operations[$operation_id][$entity_type][$cid] = FALSE; | |
} | |
} | |
- return $operations[$operation_id]; | |
+ return $operations[$operation_id][$entity_type][$cid]; | |
} | |
/** | |
@@ -638,11 +644,11 @@ function theme_views_bulk_operations_confirmation($variables) { | |
// All rows on all pages have been selected, so show a count of additional items. | |
if ($select_all_pages) { | |
$more_count = $vbo->view->total_rows - count($vbo->view->result); | |
- $items[] = t('...and <strong>!count</strong> more.', array('!count' => $more_count)); | |
+ $items[] = t('...and %count more.', array('%count' => $more_count)); | |
} | |
$count = format_plural(count($entities), 'item', '@count items'); | |
- $output = theme('item_list', array('items' => $items, 'title' => t('You selected the following <strong>!count</strong>:', array('!count' => $count)))); | |
+ $output = theme('item_list', array('items' => $items, 'title' => t('You selected the following %count:', array('%count' => $count)))); | |
return $output; | |
} | |
@@ -902,10 +908,16 @@ function views_bulk_operations_adjust_selection($queue_name, $operation, $option | |
} | |
$vbo = _views_bulk_operations_get_field($view); | |
+ | |
+ // Call views_handler_field_entity::pre_render() to get the entities. | |
+ $vbo->pre_render($view->result); | |
+ | |
$rows = array(); | |
foreach ($view->result as $row_index => $result) { | |
+ // Set the row index. | |
+ $view->row_index = $row_index; | |
$rows[$row_index] = array( | |
- 'entity_id' => $vbo->get_value($result), | |
+ 'entity_id' => $vbo->get_value($result, $vbo->real_field), | |
'views_row' => array(), | |
'position' => array( | |
'current' => ++$context['sandbox']['progress'], | |
@@ -1075,7 +1087,8 @@ function views_bulk_operations_queue_item_process($queue_item_data, &$log = NULL | |
} | |
// If the current entity can't be accessed, skip it and log a notice. | |
- if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity, $account)) { | |
+ $skip_permission_check = $operation->getAdminOption('skip_permission_check'); | |
+ if (!$skip_permission_check && !_views_bulk_operations_entity_access($operation, $entity_type, $entity, $account)) { | |
$message = 'Skipped %operation on @type %title due to insufficient permissions.'; | |
$arguments = array( | |
'%operation' => $operation->label(), | |
@@ -1127,12 +1140,22 @@ function views_bulk_operations_direct_adjust(&$selection, $vbo) { | |
if ($field_name != $vbo->options['id']) { | |
unset($view->field[$field_name]); | |
} | |
+ else { | |
+ // Get hold of the new VBO field. | |
+ $new_vbo = $view->field[$field_name]; | |
+ } | |
} | |
$view->execute($vbo->view->current_display); | |
+ | |
+ // Call views_handler_field_entity::pre_render() to get the entities. | |
+ $new_vbo->pre_render($view->result); | |
+ | |
$results = array(); | |
foreach ($view->result as $row_index => $result) { | |
- $results[$row_index] = $vbo->get_value($result); | |
+ // Set the row index. | |
+ $view->row_index = $row_index; | |
+ $results[$row_index] = $new_vbo->get_value($result, $new_vbo->real_field); | |
} | |
$selection = $results; | |
} | |
@@ -1160,9 +1183,10 @@ function views_bulk_operations_direct_process($operation, $rows, $options) { | |
} | |
$entities = _views_bulk_operations_entity_load($entity_type, $entity_ids, $options['revision']); | |
+ $skip_permission_check = $operation->getAdminOption('skip_permission_check'); | |
// Filter out entities that can't be accessed. | |
foreach ($entities as $id => $entity) { | |
- if (!_views_bulk_operations_entity_access($operation, $entity_type, $entity)) { | |
+ if (!$skip_permission_check && !_views_bulk_operations_entity_access($operation, $entity_type, $entity, $account)) { | |
$context['results']['log'][] = t('Skipped %operation on @type %title due to insufficient permissions.', array( | |
'%operation' => $operation->label(), | |
'@type' => $entity_type, | |
diff --git a/views_bulk_operations.rules.inc b/views_bulk_operations.rules.inc | |
index b3a6418..1273552 100644 | |
--- a/views_bulk_operations.rules.inc | |
+++ b/views_bulk_operations.rules.inc | |
@@ -114,15 +114,25 @@ function views_bulk_operations_rules_action_info() { | |
function views_bulk_operations_views_list() { | |
$selectable_displays = array(); | |
foreach (views_get_enabled_views() as $name => $base_view) { | |
+ $view = $base_view->clone_view(); | |
foreach ($base_view->display as $display_name => $display) { | |
- $view = $base_view->clone_view(); | |
- $view->build($display_name); | |
- $vbo = _views_bulk_operations_get_field($view); | |
- if ($vbo) { | |
- $selectable_displays[$view->name . '|' . $display_name] = check_plain($view->human_name) . ' | ' . check_plain($display->display_title); | |
+ if (!$view->set_display($display_name)) { | |
+ continue; | |
+ } | |
+ | |
+ // Initialize the style plugin and only continue to initialize handlers | |
+ // if the style uses fields. | |
+ if (!$view->init_style() || !$view->style_plugin->uses_fields()) { | |
+ continue; | |
+ } | |
+ | |
+ $view->init_handlers($display_name); | |
+ if (_views_bulk_operations_get_field($view)) { | |
+ $selectable_displays[$view->name . '|' . $display_name] = check_plain($view->human_name . ' | ' . $display->display_title); | |
} | |
} | |
} | |
+ | |
return $selectable_displays; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment