diff --git a/core/modules/comment/comment.routing.yml b/core/modules/comment/comment.routing.yml index ca37c61..575ef1f 100644 --- a/core/modules/comment/comment.routing.yml +++ b/core/modules/comment/comment.routing.yml @@ -2,7 +2,7 @@ comment.admin: path: '/admin/content/comment' defaults: _title: 'Comments' - _content: '\Drupal\comment\Controller\AdminController::adminPage' + _form: 'Drupal\comment\Form\CommentAdminOverview' type: 'new' requirements: _permission: 'administer comments' @@ -11,7 +11,7 @@ comment.admin_approval: path: '/admin/content/comment/approval' defaults: _title: 'Unapproved comments' - _content: '\Drupal\comment\Controller\AdminController::adminPage' + _form: 'Drupal\comment\Form\CommentAdminOverview' type: 'approval' requirements: _permission: 'administer comments' @@ -50,6 +50,14 @@ entity.comment.delete_form: requirements: _entity_access: 'comment.delete' +comment.multiple_delete_confirm: + path: '/admin/content/comment/delete' + defaults: + _title: 'Delete' + _form: '\Drupal\comment\Form\ConfirmDeleteMultiple' + requirements: + _permission: 'administer comments' + comment.reply: path: '/comment/reply/{entity_type}/{entity}/{field_name}/{pid}' defaults: diff --git a/core/modules/comment/comment.views.inc b/core/modules/comment/comment.views.inc index cdd7ec0..ca0f432 100644 --- a/core/modules/comment/comment.views.inc +++ b/core/modules/comment/comment.views.inc @@ -88,6 +88,13 @@ function comment_views_data_alter(&$data) { ), ); } + $data['comment']['comment_bulk_form'] = array( + 'title' => t('Comment operations bulk form'), + 'help' => t('Add a form element that lets you run operations on multiple comments.'), + 'field' => array( + 'id' => 'comment_bulk_form', + ), + ); } } } diff --git a/core/modules/comment/config/install/system.action.comment_delete_action.yml b/core/modules/comment/config/install/system.action.comment_delete_action.yml new file mode 100644 index 0000000..5034172 --- /dev/null +++ b/core/modules/comment/config/install/system.action.comment_delete_action.yml @@ -0,0 +1,7 @@ +id: comment_delete_action +label: 'Delete comment' +status: true +langcode: en +type: comment +plugin: comment_delete_action +configuration: { } diff --git a/core/modules/comment/config/install/views.view.comment.yml b/core/modules/comment/config/install/views.view.comment.yml new file mode 100644 index 0000000..b8965ce --- /dev/null +++ b/core/modules/comment/config/install/views.view.comment.yml @@ -0,0 +1,1226 @@ +base_field: cid +base_table: comment +core: 8.x +description: 'Find and manage comments.' +status: true +display: + default: + display_plugin: default + id: default + display_title: Master + position: 1 + display_options: + access: + type: perm + options: + perm: 'administer comments' + cache: + type: none + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + slave: false + query_comment: false + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: full + options: + items_per_page: 50 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 20, 40, 60' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: '‹ previous' + next: 'next ›' + first: '« first' + last: 'last »' + quantity: 9 + style: + type: table + options: + grouping: { } + row_class: '' + default_row_class: true + override: true + sticky: false + caption: '' + summary: '' + description: '' + columns: + subject: subject + name: name + title: title + edit_comment: edit_comment + dropbutton: dropbutton + translation_link: translation_link + changed: changed + info: + subject: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + name: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-medium + title: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-low + edit_comment: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + dropbutton: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + translation_link: + align: '' + separator: '' + empty_column: false + responsive: '' + changed: + sortable: true + default_sort_order: desc + align: '' + separator: '' + empty_column: false + responsive: priority-low + default: changed + empty_table: false + row: + type: fields + relationships: + node: + id: node + table: comment + field: node + required: true + relationship: none + group_type: group + admin_label: Content + fields: + comment_bulk_form: + id: comment_bulk_form + table: comment + field: comment_bulk_form + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + action_title: 'Update Options' + include_exclude: include + selected_actions: + comment_delete_action: comment_delete_action + comment_unpublish_action: comment_unpublish_action + plugin_id: comment_bulk_form + provider: comment + subject: + id: subject + table: comment + field: subject + relationship: none + group_type: group + admin_label: '' + label: Subject + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: false + ellipsis: false + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + link_to_comment: true + link_to_entity: false + plugin_id: comment + provider: comment + name: + id: name + table: comment + field: name + relationship: none + group_type: group + admin_label: '' + label: Author + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + link_to_user: true + plugin_id: comment_username + provider: comment + title: + id: title + table: node_field_data + field: title + relationship: node + group_type: group + admin_label: '' + label: 'Posted in' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + link_to_node: true + plugin_id: node + provider: node + changed: + id: changed + table: comment + field: changed + relationship: none + group_type: group + admin_label: '' + label: Updated + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + date_format: short + custom_date_format: '' + timezone: '' + plugin_id: date + provider: views + edit_comment: + id: edit_comment + table: comment + field: edit_comment + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: edit + link_to_entity: false + destination: false + plugin_id: comment_link_edit + provider: comment + delete_comment: + id: delete_comment + table: comment + field: delete_comment + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: delete + link_to_entity: false + plugin_id: comment_link_delete + provider: comment + translation_link: + id: translation_link + table: comment + field: translation_link + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: translate + plugin_id: content_translation_link + provider: content_translation + dropbutton: + id: dropbutton + table: views + field: dropbutton + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + fields: + edit_comment: edit_comment + delete_comment: delete_comment + translation_link: translation_link + action_bulk_form: '0' + subject: '0' + name: '0' + title: '0' + changed: '0' + destination: true + plugin_id: dropbutton + provider: views + filters: + status: + value: true + table: comment + field: status + provider: comment + id: status + expose: + operator: '' + group: 1 + plugin_id: boolean + sorts: + changed: + id: changed + table: comment + field: changed + relationship: none + group_type: group + admin_label: '' + order: DESC + exposed: false + expose: + label: '' + granularity: second + plugin_id: date + provider: views + title: Comment + header: { } + footer: { } + empty: + area: + id: area + table: views + field: area + relationship: none + group_type: group + admin_label: '' + empty: true + tokenize: false + content: 'No comments available.' + format: basic_html + plugin_id: text + provider: views + arguments: { } + page_1: + display_plugin: page + id: page_1 + display_title: 'Published Comments' + position: 1 + display_options: + path: admin/content/comment + menu: + type: tab + title: Comments + description: 'Comments published' + name: admin + weight: 0 + context: '0' + display_description: '' + page_2: + display_plugin: page + id: page_2 + display_title: 'Unapproved Comments' + position: 2 + display_options: + path: admin/content/comment/approval + menu: + type: tab + title: 'Unapproved comments' + description: 'Comments unapproved' + name: admin + weight: 1 + context: '0' + display_description: '' + filters: + status: + id: status + table: comment + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: false + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + plugin_id: boolean + provider: comment + defaults: + filters: false + filter_groups: false + fields: false + filter_groups: + operator: AND + groups: + 1: AND + fields: + comment_bulk_form: + id: comment_bulk_form + table: comment + field: comment_bulk_form + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + action_title: 'Update Options' + include_exclude: include + selected_actions: + comment_delete_action: comment_delete_action + comment_publish_action: comment_publish_action + plugin_id: comment_bulk_form + provider: comment + subject: + id: subject + table: comment + field: subject + relationship: none + group_type: group + admin_label: '' + label: Subject + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: false + ellipsis: false + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + link_to_comment: true + link_to_entity: false + plugin_id: comment + provider: comment + name: + id: name + table: comment + field: name + relationship: none + group_type: group + admin_label: '' + label: Author + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + link_to_user: true + plugin_id: comment_username + provider: comment + title: + id: title + table: node_field_data + field: title + relationship: node + group_type: group + admin_label: '' + label: 'Posted in' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + link_to_node: true + plugin_id: node + provider: node + changed: + id: changed + table: comment + field: changed + relationship: none + group_type: group + admin_label: '' + label: Updated + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + date_format: short + custom_date_format: '' + timezone: '' + plugin_id: date + provider: views + edit_comment: + id: edit_comment + table: comment + field: edit_comment + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: edit + link_to_entity: false + destination: false + plugin_id: comment_link_edit + provider: comment + delete_comment: + id: delete_comment + table: comment + field: delete_comment + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: delete + link_to_entity: false + plugin_id: comment_link_delete + provider: comment + translation_link: + id: translation_link + table: comment + field: translation_link + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + text: translate + plugin_id: content_translation_link + provider: content_translation + dropbutton: + id: dropbutton + table: views + field: dropbutton + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: '' + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + fields: + edit_comment: edit_comment + delete_comment: delete_comment + translation_link: translation_link + action_bulk_form: '0' + subject: '0' + name: '0' + title: '0' + changed: '0' + destination: true + plugin_id: dropbutton + provider: views +label: Comment +module: views +id: comment +tag: '' +langcode: en +dependencies: + module: + - comment + - content_translation + - node diff --git a/core/modules/comment/config/schema/comment.schema.yml b/core/modules/comment/config/schema/comment.schema.yml index b5bcd86..99dcd1e 100644 --- a/core/modules/comment/config/schema/comment.schema.yml +++ b/core/modules/comment/config/schema/comment.schema.yml @@ -112,3 +112,7 @@ field.comment.field_settings: preview: type: integer label: 'Preview comment' + +action.configuration.comment_delete_action: + type: action_configuration_default + label: 'Delete comment configuration' diff --git a/core/modules/comment/config/schema/comment.views.schema.yml b/core/modules/comment/config/schema/comment.views.schema.yml index 0bd1332..6f913d8 100644 --- a/core/modules/comment/config/schema/comment.views.schema.yml +++ b/core/modules/comment/config/schema/comment.views.schema.yml @@ -27,6 +27,20 @@ views.field.comment_entity_link: type: boolean label: 'Show teaser-style link' +views.field.comment_bulk_form: + type: views_field_bulk_form + label: 'Comment bulk form' + mapping: + include_exclude: + type: string + label: 'Available actions' + selected_actions: + type: sequence + label: 'Available actions' + sequence: + - type: string + label: 'Action' + views.field.comment_last_timestamp: type: views.field.date label: 'Last comment date' @@ -36,10 +50,10 @@ views.field.comment_link: label: 'Comment link' mapping: text: - type: views_field + type: label label: 'Text to display' link_to_entity: - type: views_field + type: boolean label: 'Link field to the entity if there is no comment' views.field.comment_link_approve: diff --git a/core/modules/comment/src/Controller/AdminController.php b/core/modules/comment/src/Controller/AdminController.php index 4c1592f..c6ffa11 100644 --- a/core/modules/comment/src/Controller/AdminController.php +++ b/core/modules/comment/src/Controller/AdminController.php @@ -10,6 +10,8 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Form\FormBuilderInterface; use Symfony\Component\HttpFoundation\Request; +use Drupal\comment\CommentManagerInterface; +use Drupal\field\FieldInfo; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -18,32 +20,33 @@ class AdminController extends ControllerBase { /** - * The form builder. + * Constructs an AdminController object. * - * @var \Drupal\Core\Form\FormBuilderInterface + * @param \Drupal\field\FieldInfo $field_info + * The field info service. + * @param \Drupal\comment\CommentManagerInterface $comment_manager + * The comment manager service. + * @param \Drupal\Core\Form\FormBuilderInterface $form_builder + * The form builder. */ - protected $formBuilder; + public function __construct(CommentManagerInterface $comment_manager, FieldInfo $field_info, FormBuilderInterface $form_builder) { + $this->commentManager = $comment_manager; + $this->fieldInfo = $field_info; + $this->formBuilder = $form_builder; + } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( + $container->get('comment.manager'), + $container->get('field.info'), $container->get('form_builder') ); } /** - * Constructs an AdminController object. - * - * @param \Drupal\Core\Form\FormBuilderInterface $form_builder - * The form builder. - */ - public function __construct(FormBuilderInterface $form_builder) { - $this->formBuilder = $form_builder; - } - - /** * Presents an administrative comment listing. * * @param \Symfony\Component\HttpFoundation\Request $request @@ -64,4 +67,63 @@ public function adminPage(Request $request, $type = 'new') { } } + /** + * Returns an overview of the entity types a comment field is attached to. + * + * @param string $commented_entity_type + * The entity type to which the comment field is attached. + * @param string $field_name + * The comment field for which the overview is to be displayed. + * + * @return array + * A renderable array containing the list of entity types and bundle + * combinations on which the comment field is in use. + */ + public function bundleInfo($commented_entity_type, $field_name) { + // Add a link to manage entity fields if the Field UI module is enabled. + $field_ui_enabled = $this->moduleHandler()->moduleExists('field_ui'); + + $field_info = $this->fieldInfo->getField($commented_entity_type, $field_name); + + $entity_type_info = $this->entityManager()->getDefinition($commented_entity_type); + $entity_bundle_info = $this->entityManager()->getBundleInfo($commented_entity_type); + + $build['usage'] = array( + '#theme' => 'item_list', + '#title' => String::checkPlain($entity_type_info->getLabel()), + '#items' => array(), + ); + // Loop over all of bundles to which this comment field is attached. + foreach ($field_info->getBundles() as $bundle) { + // Add the current instance to the list of bundles. + if ($field_ui_enabled && $route_info = FieldUI::getOverviewRouteInfo($commented_entity_type, $bundle)) { + // Add a link to configure the fields on the given bundle and entity + // type combination. + $build['usage']['#items'][] = $this->l($entity_bundle_info[$bundle]['label'], $route_info['route_name'], $route_info['route_parameters']); + } + else { + // Field UI is disabled so fallback to a list of bundle labels + // instead of links to configure fields. + $build['usage']['#items'][] = String::checkPlain($entity_bundle_info[$bundle]['label']); + } + } + + return $build; + } + + /** + * Route title callback. + * + * @param string $commented_entity_type + * The entity type to which the comment field is attached. + * @param string $field_name + * The comment field for which the overview is to be displayed. + * + * @return string + * The human readable field name. + */ + public function bundleTitle($commented_entity_type, $field_name) { + return $this->commentManager->getFieldUIPageTitle($commented_entity_type, $field_name); + } + } diff --git a/core/modules/comment/src/Form/CommentAdminOverview.php b/core/modules/comment/src/Form/CommentAdminOverview.php index 4abff68..7d02d6b 100644 --- a/core/modules/comment/src/Form/CommentAdminOverview.php +++ b/core/modules/comment/src/Form/CommentAdminOverview.php @@ -9,6 +9,7 @@ use Drupal\comment\CommentInterface; use Drupal\comment\CommentStorageInterface; +use Drupal\user\TempStoreFactory; use Drupal\Component\Utility\Unicode; use Drupal\Core\Datetime\DateFormatter; use Drupal\Core\Entity\EntityManagerInterface; @@ -52,6 +53,13 @@ class CommentAdminOverview extends FormBase { protected $moduleHandler; /** + * The tempstore factory. + * + * @var \Drupal\user\TempStoreFactory + */ + protected $tempStoreFactory; + + /** * Creates a CommentAdminOverview form. * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager @@ -62,12 +70,15 @@ class CommentAdminOverview extends FormBase { * The date formatter service. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler * The module handler. + * @param \Drupal\user\TempStoreFactory $temp_store_factory + * The tempstore factory. */ - public function __construct(EntityManagerInterface $entity_manager, CommentStorageInterface $comment_storage, DateFormatter $date_formatter, ModuleHandlerInterface $module_handler) { + public function __construct(EntityManagerInterface $entity_manager, CommentStorageInterface $comment_storage, DateFormatter $date_formatter, ModuleHandlerInterface $module_handler, TempStoreFactory $temp_store_factory) { $this->entityManager = $entity_manager; $this->commentStorage = $comment_storage; $this->dateFormatter = $date_formatter; $this->moduleHandler = $module_handler; + $this->tempStoreFactory = $temp_store_factory; } /** @@ -78,7 +89,8 @@ public static function create(ContainerInterface $container) { $container->get('entity.manager'), $container->get('entity.manager')->getStorage('comment'), $container->get('date.formatter'), - $container->get('module_handler') + $container->get('module_handler'), + $container->get('user.tempstore') ); } @@ -262,23 +274,32 @@ public function validateForm(array &$form, FormStateInterface $form_state) { public function submitForm(array &$form, FormStateInterface $form_state) { $operation = $form_state->getValue('operation'); $cids = $form_state->getValue('comments'); - - foreach ($cids as $cid) { - // Delete operation handled in \Drupal\comment\Form\ConfirmDeleteMultiple - // see \Drupal\comment\Controller\AdminController::adminPage(). - if ($operation == 'unpublish') { - $comment = $this->commentStorage->load($cid); - $comment->setPublished(FALSE); - $comment->save(); - } - elseif ($operation == 'publish') { - $comment = $this->commentStorage->load($cid); - $comment->setPublished(TRUE); - $comment->save(); + if ($operation != 'delete') { + foreach ($cids as $cid) { + // Delete operation handled in \Drupal\comment\Form\ConfirmDeleteMultiple + // see \Drupal\comment\Controller\AdminController::adminPage(). + if ($operation == 'unpublish') { + $comment = $this->commentStorage->load($cid); + $comment->setPublished(FALSE); + $comment->save(); + } + elseif ($operation == 'publish') { + $comment = $this->commentStorage->load($cid); + $comment->setPublished(TRUE); + $comment->save(); + } } + drupal_set_message($this->t('The update has been performed.')); + $form_state->setRedirect('comment.admin'); + Cache::invalidateTags(array('content' => TRUE)); + } + else { + $this->tempStoreFactory + ->get('comment_multiple_delete_confirm') + ->set(\Drupal::currentUser() + ->id(), $this->commentStorage->loadMultiple($cids)); + $form_state->setRedirect('comment.multiple_delete_confirm'); } - drupal_set_message($this->t('The update has been performed.')); - $form_state->setRedirect('comment.admin'); } } diff --git a/core/modules/comment/src/Form/ConfirmDeleteMultiple.php b/core/modules/comment/src/Form/ConfirmDeleteMultiple.php index f6c8a6e..73edf25 100644 --- a/core/modules/comment/src/Form/ConfirmDeleteMultiple.php +++ b/core/modules/comment/src/Form/ConfirmDeleteMultiple.php @@ -8,10 +8,12 @@ namespace Drupal\comment\Form; use Drupal\comment\CommentStorageInterface; +use Drupal\user\TempStoreFactory; use Drupal\Component\Utility\String; use Drupal\Core\Form\ConfirmFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Url; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -20,6 +22,13 @@ class ConfirmDeleteMultiple extends ConfirmFormBase { /** + * The tempstore factory. + * + * @var \Drupal\user\TempStoreFactory + */ + protected $tempStoreFactory; + + /** * The comment storage. * * @var \Drupal\comment\CommentStorageInterface @@ -38,9 +47,12 @@ class ConfirmDeleteMultiple extends ConfirmFormBase { * * @param \Drupal\comment\CommentStorageInterface $comment_storage * The comment storage. + * @param \Drupal\user\TempStoreFactory $temp_store_factory + * The tempstore factory. */ - public function __construct(CommentStorageInterface $comment_storage) { + public function __construct(CommentStorageInterface $comment_storage, TempStoreFactory $temp_store_factory) { $this->commentStorage = $comment_storage; + $this->tempStoreFactory = $temp_store_factory; } /** @@ -48,7 +60,8 @@ public function __construct(CommentStorageInterface $comment_storage) { */ public static function create(ContainerInterface $container) { return new static( - $container->get('entity.manager')->getStorage('comment') + $container->get('entity.manager')->getStorage('comment'), + $container->get('user.tempstore') ); } @@ -63,7 +76,7 @@ public function getFormId() { * {@inheritdoc} */ public function getQuestion() { - return $this->t('Are you sure you want to delete these comments and all their children?'); + return $this->formatPlural(count($this->comments), 'Are you sure you want to delete this comment and all its children?', 'Are you sure you want to delete these comments and all their children?'); } /** @@ -77,7 +90,7 @@ public function getCancelUrl() { * {@inheritdoc} */ public function getConfirmText() { - return $this->t('Delete comments'); + return $this->t('Delete'); } /** @@ -85,12 +98,18 @@ public function getConfirmText() { */ public function buildForm(array $form, FormStateInterface $form_state) { $edit = $form_state->getUserInput(); + $this->comments = $this->tempStoreFactory->get('comment_multiple_delete_confirm')->get(\Drupal::currentUser()->id()); + if (empty($this->comments)) { + return new RedirectResponse($this->urlGenerator() + ->generate('comment.admin')); + } $form['comments'] = array( '#prefix' => '', '#tree' => TRUE, ); + // array_filter() returns only elements with actual values. $comment_counter = 0; $this->comments = $this->commentStorage->loadMultiple(array_keys(array_filter($edit['comments']))); @@ -102,15 +121,9 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#prefix' => '
  • ', '#suffix' => String::checkPlain($comment->label()) . '
  • ' ); - $comment_counter++; } $form['operation'] = array('#type' => 'hidden', '#value' => 'delete'); - if (!$comment_counter) { - drupal_set_message($this->t('There do not appear to be any comments to delete, or your selected comment was deleted by another administrator.')); - $form_state->setRedirect('comment.admin'); - } - return parent::buildForm($form, $form_state); } @@ -118,11 +131,12 @@ public function buildForm(array $form, FormStateInterface $form_state) { * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { - if ($form_state->getValue('confirm')) { + if ($form_state->getValue('confirm') && !empty($this->comments)) { $this->commentStorage->delete($this->comments); - $count = count($form_state->getValue('comments')); + $this->tempStoreFactory->get('comment_multiple_delete_confirm')->delete(\Drupal::currentUser()->id()); + $count = count($this->comments); $this->logger('content')->notice('Deleted @count comments.', array('@count' => $count)); - drupal_set_message(format_plural($count, 'Deleted 1 comment.', 'Deleted @count comments.')); + drupal_set_message($this->formatPlural($count, 'Deleted 1 comment.', 'Deleted @count comments.')); } $form_state->setRedirectUrl($this->getCancelUrl()); } diff --git a/core/modules/comment/src/Plugin/Action/DeleteComment.php b/core/modules/comment/src/Plugin/Action/DeleteComment.php new file mode 100644 index 0000000..1f0bd48 --- /dev/null +++ b/core/modules/comment/src/Plugin/Action/DeleteComment.php @@ -0,0 +1,73 @@ +tempStore = $temp_store_factory->get('comment_multiple_delete_confirm'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static($configuration, $plugin_id, $plugin_definition, $container->get('user.tempstore')); + } + + /** + * {@inheritdoc} + */ + public function executeMultiple(array $entities) { + $this->tempStore->set(\Drupal::currentUser()->id(), $entities); + } + + /** + * {@inheritdoc} + */ + public function execute($entity = NULL) { + $this->executeMultiple(array($entity)); + } + +} diff --git a/core/modules/comment/src/Plugin/views/field/CommentBulkForm.php b/core/modules/comment/src/Plugin/views/field/CommentBulkForm.php new file mode 100644 index 0000000..dae4b7a --- /dev/null +++ b/core/modules/comment/src/Plugin/views/field/CommentBulkForm.php @@ -0,0 +1,121 @@ +actions = array_filter($this->actions, function ($action) { + return $action->getType() == 'comment'; + }); + + } + + /** + * {@inheritdoc} + */ + protected function defineOptions() { + $options = parent::defineOptions(); + $options['include_exclude'] = array( + 'default' => 'exclude', + ); + $options['selected_actions'] = array( + 'default' => array(), + ); + return $options; + } + + /** + * {@inheritdoc} + */ + public function buildOptionsForm(&$form, &$form_state) { + parent::buildOptionsForm($form, $form_state); + + $form['include_exclude'] = array( + '#type' => 'radios', + '#title' => t('Available actions'), + '#options' => array( + 'exclude' => t('All actions, except selected'), + 'include' => t('Only selected actions'), + ), + '#default_value' => $this->options['include_exclude'], + ); + $form['selected_actions'] = array( + '#type' => 'checkboxes', + '#title' => t('Selected actions'), + '#options' => $this->getBulkOptions(FALSE), + '#default_value' => $this->options['selected_actions'], + ); + } + + /** + * {@inheritdoc} + */ + public function validateOptionsForm(&$form, &$form_state) { + parent::validateOptionsForm($form, $form_state); + + $form_state['values']['options']['selected_actions'] = array_filter($form_state['values']['options']['selected_actions']); + } + + /** + * {@inheritdoc} + */ + protected function getBulkOptions($filtered = TRUE) { + // Get all available actions. + $entity_type = $this->getEntityType(); + $options = array(); + // Filter the action list. + foreach ($this->actions as $id => $action) { + if ($filtered) { + $in_selected = in_array($id, $this->options['selected_actions']); + // If the field is configured to include only the selected actions, + // skip actions that were not selected. + if (($this->options['include_exclude'] == 'include') && !$in_selected) { + continue; + } + // Otherwise, if the field is configured to exclude the selected + // actions, skip actions that were selected. + elseif (($this->options['include_exclude'] == 'exclude') && $in_selected) { + continue; + } + } + // Only allow actions that are valid for this entity type. + if (($action->getType() == $entity_type)) { + $options[$id] = $action->label(); + } + } + + return $options; + } + + /** + * {@inheritdoc} + */ + public function views_form_validate(&$form, &$form_state) { + $selected = array_filter($form_state['values'][$this->options['id']]); + if (empty($selected)) { + $this->formBuilder->setErrorByName('', $form_state, t('No comments selected.')); + } + } + +} diff --git a/core/modules/comment/src/Plugin/views/field/LinkEdit.php b/core/modules/comment/src/Plugin/views/field/LinkEdit.php index 4e687a3..eb18018 100644 --- a/core/modules/comment/src/Plugin/views/field/LinkEdit.php +++ b/core/modules/comment/src/Plugin/views/field/LinkEdit.php @@ -51,7 +51,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { protected function renderLink($data, ResultRow $values) { parent::renderLink($data, $values); // Ensure user has access to edit this comment. - $comment = $this->getValue($values); + $comment = $data; if (!$comment->access('update')) { return; } diff --git a/core/modules/comment/src/Tests/CommentAdminTest.php b/core/modules/comment/src/Tests/CommentAdminTest.php index 811dfde..ce92058 100644 --- a/core/modules/comment/src/Tests/CommentAdminTest.php +++ b/core/modules/comment/src/Tests/CommentAdminTest.php @@ -85,7 +85,7 @@ function testApprovalAdminInterface() { ); $this->drupalPostForm(NULL, $edit, t('Update')); $this->assertText(t('Are you sure you want to delete these comments and all their children?'), 'Confirmation required.'); - $this->drupalPostForm(NULL, $edit, t('Delete comments')); + $this->drupalPostForm(NULL, $edit, t('Delete')); $this->assertText(t('No comments available.'), 'All comments were deleted.'); // Test message when no comments selected. $edit = array( diff --git a/core/modules/comment/src/Tests/CommentNonNodeTest.php b/core/modules/comment/src/Tests/CommentNonNodeTest.php index 15eb7b7..4beaf32 100644 --- a/core/modules/comment/src/Tests/CommentNonNodeTest.php +++ b/core/modules/comment/src/Tests/CommentNonNodeTest.php @@ -204,7 +204,7 @@ function performCommentOperation($comment, $operation, $approval = FALSE) { $this->drupalPostForm('admin/content/comment' . ($approval ? '/approval' : ''), $edit, t('Update')); if ($operation == 'delete') { - $this->drupalPostForm(NULL, array(), t('Delete comments')); + $this->drupalPostForm(NULL, array(), t('Delete')); $this->assertRaw(format_plural(1, 'Deleted 1 comment.', 'Deleted @count comments.'), format_string('Operation "@operation" was performed on comment.', array('@operation' => $operation))); } else { diff --git a/core/modules/comment/src/Tests/CommentTestBase.php b/core/modules/comment/src/Tests/CommentTestBase.php index d86e3d4..0b3177f 100644 --- a/core/modules/comment/src/Tests/CommentTestBase.php +++ b/core/modules/comment/src/Tests/CommentTestBase.php @@ -344,7 +344,7 @@ function performCommentOperation(CommentInterface $comment, $operation, $approva $this->drupalPostForm('admin/content/comment' . ($approval ? '/approval' : ''), $edit, t('Update')); if ($operation == 'delete') { - $this->drupalPostForm(NULL, array(), t('Delete comments')); + $this->drupalPostForm(NULL, array(), t('Delete')); $this->assertRaw(format_plural(1, 'Deleted 1 comment.', 'Deleted @count comments.'), format_string('Operation "@operation" was performed on comment.', array('@operation' => $operation))); } else { diff --git a/core/modules/node/tests/src/Unit/Plugin/views/field/NodeBulkFormTest.php b/core/modules/node/tests/src/Unit/Plugin/views/field/NodeBulkFormTest.php index 82836e0..8d19df8 100644 --- a/core/modules/node/tests/src/Unit/Plugin/views/field/NodeBulkFormTest.php +++ b/core/modules/node/tests/src/Unit/Plugin/views/field/NodeBulkFormTest.php @@ -80,7 +80,8 @@ public function testConstructor() { $definition['title'] = ''; $options = array(); - $node_bulk_form = new NodeBulkForm(array(), 'node_bulk_form', $definition, $entity_storage); + $form_error = $this->getMock('Drupal\Core\Form\FormErrorInterface'); + $node_bulk_form = new NodeBulkForm(array(), 'node_bulk_form', $definition, $entity_storage, $form_error); $node_bulk_form->init($executable, $display, $options); $this->assertAttributeEquals(array_slice($actions, 0, -1, TRUE), 'actions', $node_bulk_form); diff --git a/core/modules/user/tests/src/Unit/Plugin/views/field/UserBulkFormTest.php b/core/modules/user/tests/src/Unit/Plugin/views/field/UserBulkFormTest.php index 0e0b44e..8c1ddbb 100644 --- a/core/modules/user/tests/src/Unit/Plugin/views/field/UserBulkFormTest.php +++ b/core/modules/user/tests/src/Unit/Plugin/views/field/UserBulkFormTest.php @@ -80,7 +80,8 @@ public function testConstructor() { $definition['title'] = ''; $options = array(); - $user_bulk_form = new UserBulkForm(array(), 'user_bulk_form', $definition, $entity_storage); + $form_error = $this->getMock('Drupal\Core\Form\FormErrorInterface'); + $user_bulk_form = new UserBulkForm(array(), 'user_bulk_form', $definition, $entity_storage, $form_error); $user_bulk_form->init($executable, $display, $options); $this->assertAttributeEquals(array_slice($actions, 0, -1, TRUE), 'actions', $user_bulk_form); diff --git a/core/modules/views/src/Tests/DefaultViewsTest.php b/core/modules/views/src/Tests/DefaultViewsTest.php index 15b49a4..5c89287 100644 --- a/core/modules/views/src/Tests/DefaultViewsTest.php +++ b/core/modules/views/src/Tests/DefaultViewsTest.php @@ -140,10 +140,6 @@ public function testDefaultViews() { $tokens = array('@name' => $name, '@display_id' => $display_id); $this->assertTrue($view->executed, format_string('@name:@display_id has been executed.', $tokens)); - - $count = count($view->result); - $this->assertTrue($count > 0, format_string('@count results returned', array('@count' => $count))); - $view->destroy(); } } }