monster_menus-9.0.x-dev/mm_ui.inc
mm_ui.inc
<?php
/**
* @file
* User interface routines for monster_menus
*/
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Database\Database;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Render\Element;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
use Drupal\filter\Render\FilteredMarkup;
use Drupal\monster_menus\Constants;
use Drupal\monster_menus\Controller\DefaultController;
use Drupal\monster_menus\Form\AddGroupUsersForm;
use Drupal\monster_menus\PermissionsSolver;
use Drupal\monster_menus\Plugin\MMTreeBrowserDisplay\Groups;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Symfony\Component\HttpFoundation\RedirectResponse;
function mm_ui_machine_name_exists() {
// This is a dummy function. The real validation is handled elsewhere.
return FALSE;
}
/**
* Implements hook_form_BASE_FORM_ID_alter(). (admin/structure/types/manage)
*/
function monster_menus_form_node_type_form_alter(&$form) {
if (isset($form['comment']['comment'])) {
$form['comment']['comment']['#description'] = t('Users with the <em>administer comments</em> or <em>enable/disable comments</em> permission will be able to override this setting.');
}
if (isset($form['display']['node_submitted'])) {
$form['display']['node_submitted']['#description'] = t('Because you are using Monster Menus, the setting for <em>Submitted by [username] on [date]</em> text is controlled independently, within each piece of content. The setting here acts as a global override for all content of the given type. If not checked, the text is never displayed for this type of content.');
}
$form['mm_default_region'] = [
'#type' => 'details',
'#title' => t('Default region'),
'#description' => t('This setting controls where new content of this type will appear on the page, by default. After the node has been saved, its location can be changed with the <em>Reorder</em> tab.'),
'#group' => 'additional_settings',
];
_mm_ui_get_regions($regions, $select);
foreach ($regions as $region => $data) {
$form['mm_default_region'][] = [
'#type' => 'container',
'#input' => FALSE,
'#markup' => $data['message'],
'#states' => ['visible' => [':input[name="mm_default_region"]' => ['value' => $region]]],
];
}
$defaults = mm_get_setting('nodes.default_region');
$form['mm_default_region']['mm_default_region'] = [
'#type' => 'select',
'#title' => t('Default region for newly created nodes'),
'#options' => $select,
'#default_value' => $defaults[$form['type']['#default_value']] ?? Constants::MM_UI_REGION_CONTENT,
'#weight' => -1,
];
// Adding to $form['#submit'] doesn't work.
$form['actions']['submit']['#submit'][] = '_mm_ui_submit_region';
}
function _mm_ui_submit_region($form, FormStateInterface $form_state) {
$config = \Drupal::service('config.factory')->getEditable('monster_menus.settings');
$defaults = $config->get('nodes.default_region');
$defaults[$form_state->getValue('type')] = $form_state->getValue('mm_default_region');
$config
->set('nodes.default_region', $defaults)
->save();
}
function _mm_ui_get_regions(&$regions, &$select, $li = TRUE) {
$regions = [];
$num_themes = 0;
foreach (\Drupal::service('theme_handler')->listInfo() as $theme => $data) {
if ($data->status) {
$num_themes++;
foreach ($data->info['regions'] as $region => $long_name) {
if (!isset($data->info['regions_hidden']) || !in_array($region, $data->info['regions_hidden'])) {
$regions[$region]['long_name'] = $long_name;
$regions[$region]['themes'][] = $theme;
}
}
}
}
uasort($regions, fn($a, $b) => strcasecmp($a['long_name'], $b['long_name']));
$select = [];
foreach ($regions as $region => $data) {
natcasesort($data['themes']);
$list = count($data['themes']) == $num_themes ? t('all themes') : implode(', ', $data['themes']);
if (mb_strlen($list) > 50) {
$list = Unicode::truncateBytes($list, 50) . '...';
}
$select[$region] = $data['long_name'] . ' (' . $list . ')';
if (count($data['themes']) == $num_themes) {
$regions[$region]['message'] = t('The selected region is used in all themes.');
}
else {
$msg = t('The selected region is used in the following theme(s):');
if ($li) {
$regions[$region]['message'] = $msg . '<ul><li>' . implode('</li><li>', $data['themes']) . '</li>';
}
else {
$regions[$region]['message'] = $msg . ' ' . implode(', ', $data['themes']);
}
}
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*
* Adjust a couple of form elements on the block admin page.
*/
function monster_menus_form_block_form_alter(&$form, FormState &$form_state, $form_id) {
if ($form_state->getTemporaryValue('is_mm_block')) {
$form['settings']['label']['#title'] = t('Internal title');
$form['settings']['label']['#description'] = t('The name visible to users in the Appearance settings for a @thing', mm_ui_strings(FALSE));
// Visibility settings are not meaningful for MM blocks
$form['visibility']['#access'] = FALSE;
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*
* Remove some unneeded node creation options, and add some of our own. This
* only works if MM happens to load after the modules that create these form
* elements.
*/
function monster_menus_form_node_form_alter(&$form, FormState &$form_state, $form_id) {
/** @var NodeInterface $node */
$db = Database::getConnection();
$node = $form_state->getFormObject()->getEntity();
$comment_fields = _mm_ui_get_comment_fields($node, $form);
// Note: this cannot be turned into a lambda/closure because the form array
// needs to be serializable for the Preview function to work.
$form['#entity_builders'][] = '_monster_menus_node_builder';
mm_parse_args($mmtids, $oarg_list, $this_mmtid);
$mmlist = $mmlist_restricted = $mmlist_restricted_link = [];
$mmlist_valid = FALSE;
if ($form_state->isRebuilding()) { // user clicked Preview button
$values = $form_state->getValues();
[$grouplist, $users, $others] = _mm_ui_form_parse_perms($form_state, (object) $values, FALSE);
$userlist = [];
foreach ($users as $uid => $data) {
$userlist[$uid] = $data['name'];
}
$everyone = !empty($others);
$uid = isset($values['owner']) ? intval($values['owner']) : 1;
if (isset($values['mm_catlist'])) {
$mmlist = $values['mm_catlist'];
$mmlist_restricted = $values['mm_catlist_restricted'] ?? [];
$mmlist_restricted_link = $values['mm_catlist_restricted_link'] ?? [];
$mmlist_valid = TRUE;
}
}
if (isset($form['title'])) {
if (isset($form['title']['widget'][0]['value'])) {
if (!isset($form['title']['widget'][0]['value']['#description'])) {
$form['title']['widget'][0]['value']['#description'] = '';
}
$desc = &$form['title']['widget'][0]['value']['#description'];
}
else {
if (!isset($form['title']['#description'])) {
$form['title']['#description'] = '';
}
$desc = &$form['title']['#description'];
}
$desc = t('@previous To prevent the title from displaying when viewing a page, surround it with square brackets. Example: [My Title]', ['@previous' => $desc]);
}
if (!$node->isNew()) { // existing node
if ($mmtids) {
$form['#mm_redirect'] = mm_content_get_mmtid_url($this_mmtid);
}
if (mm_content_node_is_recycled($node, $this_mmtid)) {
_mm_ui_form_array_merge($form, 'mm_categories', ['#type' => 'details', '#title' => t('Pages'), '#group' => 'advanced', '#weight' => 120]);
_mm_ui_recycle_page_list([mm_content_get_parent($this_mmtid)], $names, $msg);
if (!$names) {
$msg = t('This content is not associated with a page. If restored, it will be visible only by its direct web address.');
}
elseif (count($names) == 1) {
$msg = t('If you restore this content, it will return to the page @link.', ['@link' => $names[0]]);
}
else {
$msg = t('If you restore this content, it will return to the following pages: @pages', ['@pages' => FilteredMarkup::create(implode(', ', $names))]);
}
$form['mm_catlist'] = [
'#type' => 'value',
'#value' => [],
];
$form['mm_catlist_restricted'] = [
'#type' => 'value',
'#value' => $node->__get('recycle_from_mmtids'),
];
// Needed for mm_content_node_is_recycled()
$form['recycle_date'] = [
'#type' => 'value',
'#value' => $node->__get('recycle_date'),
];
$form['mm_catlist_readonly'] = [
'#type' => 'container',
'#markup' => t('The list of pages cannot be changed because this content is in the recycle bin.'),
'#description' => $msg,
'#group' => 'mm_categories',
];
}
else { // !recycled
$nid = $node->id();
if ($nid && !$mmlist_valid) {
foreach (mm_content_get(mm_content_get_by_nid($nid)) as $r) {
if (mm_content_user_can($r->mmtid, Constants::MM_PERMS_APPLY)) {
$mmlist[$r->mmtid] = mm_content_get_name($r);
}
else {
$mmlist_restricted[] = $r->mmtid;
$mmlist_restricted_link[] = [':link' => mm_content_get_mmtid_url($r->mmtid), '@title' => mm_content_get_name($r)];
}
}
}
_mm_ui_form_array_merge($form, 'mm_categories', ['#type' => 'details', '#title' => t('Pages'), '#group' => 'advanced', '#weight' => 120]);
$form['mm_catlist_restricted'] = ['#type' => 'value', '#value' => $mmlist_restricted];
if ($mmlist_restricted) {
$links = ['@plur' => count($mmlist_restricted) == 1 ? t('page') : t('pages:') . ' '];
$msg = '<span style="color:red">This content will also appear on the @plur ';
foreach ($mmlist_restricted_link as $index => $link) {
if ($index > 0) {
$msg .= ', ';
}
$msg .= '<a href=":link' . $index . '">@title' . $index . '</a>';
$links[':link' . $index] = $link[':link'];
$links['@title' . $index] = $link['@title'];
}
$msg .= '. You do not have permission to change this fact.</span>';
$form['mm_catlist_warning'] = [
'#type' => 'container',
'#description' => t($msg, $links),
'#group' => 'mm_categories',
];
}
$form['mm_catlist'] = [
'#type' => 'mm_catlist',
'#description' => t('Choose one or more pages where this content will appear.'),
'#mm_list_popup_start' => implode('/', $mmtids),
'#default_value' => $mmlist,
'#group' => 'mm_categories',
];
} // if (not) recycled
if (!$form_state->isRebuilding()) {
$everyone = FALSE;
$grouplist = [];
$select = $db->select('mm_node_write', 'nw');
$select->leftJoin('mm_tree', 't', 'nw.gid = t.mmtid');
$select->fields('nw', ['gid'])
->fields('t', ['uid']);
$select->condition('nw.gid', 0, '>=');
$select->condition('nw.nid', $node->id());
$select->orderBy('t.name');
$result = $select->execute();
foreach ($result as $r) {
if ($r->gid == 0) {
$everyone = TRUE;
}
else {
$members = mm_content_get_users_in_group($r->gid, '<br />', FALSE, 20, TRUE, $form);
if ($members == '') {
$members = t('(none)');
}
$grouplist[$r->gid]['name'] = mm_content_get_name($r->gid);
if (!empty($r->uid)) {
$owner_display = ['#theme' => 'username', '#account' => User::load($r->uid)];
$owner_display = \Drupal::service('renderer')->render($owner_display);
}
else {
$owner_display = t('not available');
}
$group_display = Link::fromTextAndUrl($r->gid, mm_content_get_mmtid_url($r->gid))->toString();
$group_info_message = mm_get_setting(mm_content_is_vgroup($r->gid) ? 'vgroup.group_info_message' : 'group.group_info_message');
$group_info_message = '<div id="mmgroupinfo-' . $r->gid . '" class="hidden"><p>' . t($group_info_message, ['@gid' => $group_display, '@owner' => $owner_display]) . '</p></div>';
$group_info_link = !empty($group_info_message) ? Link::fromTextAndUrl(t('Group information'), Url::fromRoute('<current>', [], [
'fragment' => 'mmgroupinfo-' . $r->gid,
'external' => TRUE,
'attributes' => [
'id' => mm_ui_modal_dialog([], $form),
'title' => t('Information about this group'),
]
]))->toString() : '';
$grouplist[$r->gid]['members'] = (mm_content_user_can($r->gid, Constants::MM_PERMS_WRITE) ? Link::fromTextAndUrl(t('Edit this group'), Url::fromRoute('monster_menus.handle_page_settings', ['mm_tree' => $r->gid]))->toString() . ' | ' : '') . $group_info_message . $group_info_link . '<br />' . $members;
}
}
$userlist = [];
$select = $db->select('mm_node_write', 'nw')
->fields('nw', ['gid']);
$select->condition('nw.gid', 0, '<');
$select->condition('nw.nid', $node->id());
$result = $select->execute();
if ($r = $result->fetchObject()) {
$users = mm_content_get_users_in_group($r->gid, NULL, TRUE, Constants::MM_UI_MAX_USERS_IN_GROUP);
if (!is_null($users)) {
$userlist = $users;
}
}
if ($userlist || $grouplist) {
$everyone = FALSE;
}
$uid = $node->getOwnerId();
}
_mm_ui_node_form_perms($form, $userlist, $grouplist, $everyone, node_get_type_label($node), $uid);
}
else { // new node
if ($mmtids || $mmlist) {
if (!$mmlist_valid) {
$tree = mm_content_get($this_mmtid);
$mmlist = [$this_mmtid => mm_content_get_name($tree)];
mm_content_get_default_node_perms($this_mmtid, $temp_grouplist, $userlist, Constants::MM_UI_MAX_USERS_IN_GROUP);
$grouplist = [];
foreach ($temp_grouplist as $gid => $name) {
$members = mm_content_get_users_in_group($gid, '<br />', FALSE, 20, TRUE, $form);
if ($members == '') {
$members = t('(none)');
}
$grouplist[$gid]['name'] = $name;
if (!empty($tree->uid)) {
$owner_display = ['#theme' => 'username', '#account' => User::load($tree->uid)];
$owner_display = \Drupal::service('renderer')->render($owner_display);
}
else {
$owner_display = t('not available');
}
$group_display = Link::fromTextAndUrl($gid, mm_content_get_mmtid_url($gid))->toString();
$group_info_message = mm_get_setting(mm_content_is_vgroup($gid) ? 'vgroup.group_info_message' : 'group.group_info_message');
$group_info_message = '<div id="mmgroupinfo-' . $gid . '" class="hidden"><p>' . t($group_info_message, ['@gid' => $group_display, '@owner' => $owner_display]) . '</p></div>';
$group_info_link = !empty($group_info_message) ? Link::fromTextAndUrl(t('Group information'), Url::fromRoute('<current>', [], [
'fragment' => 'mmgroupinfo-' . $gid,
'external' => TRUE,
'attributes' => [
'id' => mm_ui_modal_dialog([], $form),
'title' => t('Information about this group'),
]
]))->toString() : '';
$grouplist[$gid]['members'] = (mm_content_user_can($gid, Constants::MM_PERMS_WRITE) ? Link::fromTextAndUrl(t('Edit this group'), Url::fromRoute('monster_menus.handle_page_settings', ['mm_tree' => $gid]))->toString() . ' | ' : '') . $group_info_message . $group_info_link . '<br />' . $members;
}
$uid = \Drupal::currentUser()->id();
$everyone = in_array(Constants::MM_PERMS_APPLY, explode(',', $tree->default_mode ?? ''));
$node->__set('show_node_info', $tree->node_info);
foreach ($comment_fields as $comment_field) {
$form[$comment_field]['widget'][0]['status']['#default_value'] = $tree->comment;
}
if (mm_get_setting('comments.finegrain_readability')) {
$node->__set('comments_readable', mm_content_resolve_cascaded_setting('comments_readable', $this_mmtid, $cascaded_at, $cascaded_parent));
}
else {
$node->__set('comments_readable', '');
}
}
_mm_ui_form_array_merge($form, 'mm_categories', [
'#type' => 'details',
'#title' => t('Pages'),
'#group' => 'advanced',
'#weight' => 120,
]);
$form['mm_catlist'] = [
'#type' => 'mm_catlist',
'#description' => t('Choose one or more pages where this content will appear.'),
'#mm_list_popup_start' => implode('/', $mmtids),
'#default_value' => $mmlist,
'#group' => 'mm_categories',
];
$form['mm_catlist_restricted'] = [
'#type' => 'value',
'#value' => $mmlist_restricted,
];
_mm_ui_node_form_perms($form, $userlist, $grouplist, $everyone, node_get_type_label($node), $uid);
$form['#mm_redirect'] = mm_content_get_mmtid_url($this_mmtid);
}
} // if existing/new node
if (!$form_state->get('is_mm_search') && DefaultController::menuAccessSolverByMMTID($this_mmtid)) {
PermissionsSolver::getSolverForm($form['settings_perms'], $this_mmtid);
}
$form['this_mmtid'] = [
'#type' => 'value',
'#value' => $this_mmtid
];
$form['mm_catlist_restricted_link'] = [
'#type' => 'value',
'#value' => $mmlist_restricted_link
];
unset($form['menu']);
unset($form['promote']);
unset($form['path']);
_mm_ui_form_array_merge($form, 'mm_appearance', [
'#type' => 'details',
'#title' => t('Appearance'),
'#group' => 'advanced',
'#weight' => 123,
]);
if ($form_id == 'redirect_node_form') { // redirector
// Disable comments.
foreach ($comment_fields as $comment_field) {
$form[$comment_field]['#access'] = FALSE;
$form[$comment_field]['widget'][0]['status']['#default_value'] = 0;
}
$form['options']['#access'] = FALSE;
unset($form['actions']['preview']);
$form['sticky']['#access'] = FALSE;
}
else {
// provide alternate 'sticky' checkbox
if (isset($form['sticky']['widget']['value'])) {
// Drupal defaults to only allowing Sticky for admin users. we want to let
// everyone use it.
$form['sticky']['#access'] = TRUE;
$form['sticky']['#group'] = 'mm_appearance';
$form['sticky']['widget']['value']['#title'] = t('Sticky at top of page');
$form['sticky']['widget']['value']['#description'] = t('Content that is "sticky" will stay at the top of the page, even after other content is added. But the content\'s owner must be listed under %who (see %perm, under the %set tab) in order for this setting to take effect.', ['%who' => t('Who can delete this page or change its settings'), '%perm' => t('Permissions'), '%set' => t('Settings')]);
}
}
$toggle = \Drupal::entityTypeManager()->getStorage('node_type')->load($node->getType())->displaySubmitted();
if (\Drupal::currentUser()->hasPermission('show/hide post information') && $toggle) {
$form['mm_appearance']['show_node_info'] = [
'#type' => 'select',
'#title' => t('Attribution style'),
'#options' => _mm_ui_node_info_values($form['mm_appearance']),
'#default_value' => $node->__get('show_node_info') ?? 0,
'#group' => 'mm_appearance',
];
}
else {
if (!$toggle && $node->isNew()) {
// Always default to off for new nodes when disabled in all nodes of
// this type. This way, if enabled later on for all nodes of this type,
// the end result won't immediately change.
$node->__set('show_node_info', 0);
}
$form['show_node_info'] = [
'#type' => 'value',
'#value' => $node->__get('show_node_info') ?? 0,
'#group' => 'mm_appearance',
];
}
$form['status']['#group'] = 'publishing';
// The weight of this field gets reset internally, so instead make sure that
// MM's fields come after it.
$weight = $form['status']['#weight'] ?? 0;
$form['status']['#access'] = $form_state->get('is_mm_search') || !empty($form['status']['#access']);
unset($form['options']);
_mm_ui_form_array_merge($form, 'publishing', [
'#type' => 'details',
'#title' => t('Publishing'),
'#group' => 'advanced',
'#weight' => 125,
]);
$publish_on = !empty($node->__get('publish_on')) ? DrupalDateTime::createFromTimestamp($node->__get('publish_on')) : '';
$unpublish_on = !empty($node->__get('unpublish_on')) ? DrupalDateTime::createFromTimestamp($node->__get('unpublish_on')) : '';
$t_now = ['%time' => mm_format_date(mm_request_time(), 'short')];
// For some reason, #states doesn't work to hide the individual datetime
// fields, so group them in a container and hide that.
$form['publish_settings'] = [
'#type' => 'container',
'#states' => ['visible' => ['#edit-status-value' => ['checked' => TRUE]]],
'#group' => 'publishing',
'#weight' => ++$weight,
'publish_on' => [
'#type' => 'datetime',
'#title' => t('Publish on'),
'#default_value' => $publish_on,
'#date_increment' => 60,
'#description' => t('Format: %time. Leave blank to disable scheduled publishing.', $t_now),
],
'unpublish_on' => [
'#type' => 'datetime',
'#title' => t('Unpublish on'),
'#default_value' => $unpublish_on,
'#date_increment' => 60,
'#description' => t('Format: %time. Leave blank to disable scheduled unpublishing.', $t_now),
],
'set_change_date' => [
'#type' => 'checkbox',
'#title' => t('Use <em>Publish on</em> date for attributions'),
'#default_value' => $node->set_change_date ?? '',
'#description' => t('Use the date above instead of the content\'s last modified date when showing <em>Submitted on [date]</em> or <em>Submitted by [user] on [date]</em>'),
],
];
if (isset($form['author'])) {
if (\Drupal::currentUser()->hasPermission('administer all menus')) {
// Admin users don't need the set author option, they should use "Who can edit/delete"
$form['mm_appearance']['uid'] = [
'#type' => 'item',
'#input' => FALSE,
'#title' => t('Authored by'),
'#markup' => t('<p>To change the author, set the %owner in the %where section.</p>',
[
'%owner' => t('Owner'),
'%where' => t('Who can edit or delete this content')
]),
'#group' => 'mm_appearance',
];
unset($form['uid']);
}
else {
$form['uid']['#access'] = FALSE;
}
$form['author']['#group'] = 'mm_appearance';
$form['created']['#group'] = 'mm_appearance';
}
foreach ($comment_fields as $comment_field) {
if ($finegrain = mm_get_setting('comments.finegrain_readability')) {
$form[$comment_field]['widget'][0]['comments_readable'] = [
'#type' => 'select',
'#title' => t('Who can read comments'),
'#default_value' => $node->comments_readable ?? '',
'#options' => _mm_ui_comment_read_setting_values(t('(use default setting)')),
'#weight' => -1,
];
$form[$comment_field]['widget'][0]['status']['#type'] = 'select';
$form[$comment_field]['widget'][0]['status']['#title'] = t('Who can add comments');
unset($form[$comment_field]['widget'][0]['status']['#title_display']);
}
$can_affect_comments = \Drupal::currentUser()
->hasPermission('enable/disable comments') || \Drupal::currentUser()
->hasPermission('administer comments');
$form[$comment_field]['#access'] = $can_affect_comments || $finegrain;
$form[$comment_field]['widget'][0]['status']['#access'] = $can_affect_comments;
$form[$comment_field]['widget'][0]['status']['#options'] = _mm_ui_comment_write_setting_values();
$form[$comment_field]['widget'][0]['status'][0]['#access'] = TRUE;
}
if (!$form_state->get('is_mm_search')) {
$form['actions']['required-note'] = [
'#weight' => 10000,
'#markup' => t('<div class="requiredfields"><span class="form-required"></span> denotes required fields</div>'),
];
}
if (isset($form['#mm_redirect'])) {
// Note: This cannot be inlined because serialization will fail.
$form['#validate'][] = '_mm_ui_node_form_redirect';
}
// Change the "Save and keep published/unpublish" dropbutton into a single
// submit button because we use a checkbox in the Publishing tab.
$form['actions']['submit'] = [
'#type' => 'submit',
'#submit' => $form['actions']['submit']['#submit'],
'#value' => t('Save'),
'#weight' => 0,
];
unset($form['actions']['publish']);
unset($form['actions']['unpublish']);
// Add JS code to update summaries in vertical tabs
_mm_ui_add_summary_js($form); // Initialize summaries.
foreach (['mm_appearance', 'publishing', 'settings_perms'] as $id) {
if (isset($form[$id]['#type']) && $form[$id]['#type'] == 'details') {
_mm_ui_add_summary_js($form, $id);
}
}
mm_static($form, 'mm_categories_summary', isset($form['mm_catlist_restricted']['#value']) ? count($form['mm_catlist_restricted']['#value']) : 0);
}
function _mm_ui_get_comment_fields(NodeInterface $node, array $form = NULL) {
$comment_fields = [];
foreach ($node->getFields(FALSE) as $field_name => $item_list) {
if ($item_list->getFieldDefinition()->getType() == 'comment' && (!isset($form) || isset($form[$field_name]))) {
$comment_fields[] = $field_name;
}
}
return $comment_fields;
}
function _mm_ui_node_form_redirect($form, FormStateInterface $form_state) {
if (isset($form['#mm_redirect']) && empty($form_state->getTriggeringElement()['#ajax'])) {
if ($form_state->getTriggeringElement()['#id'] == 'edit-preview') {
// Remove the destination parameter so that the user isn't redirected
// there.
\Drupal::request()->query->remove('destination');
}
else {
// The node form code always redirects to node/NN, so this is the only
// good way to make it go to the page instead.
$form_state->disableRedirect()
->setResponse(new RedirectResponse($form['#mm_redirect']->setOption('absolute', TRUE)->toString(), 303));
}
}
}
function monster_menus_form_user_role_form_alter(&$form) {
_mm_ui_form_array_merge($form, 'mm_group', [
'#type' => 'details',
'#title' => t('Add group members'),
'#description' => t('The members of the chosen Monster Menus group will be added to this role.'),
'#open' => TRUE]);
$current = isset($form['id']['#default_value']) ? Role::load($form['id']['#default_value']) : Role::create();
$form['mm_group']['mm_gid'] = [
'#type' => 'mm_grouplist',
'#mm_list_popup_start' => mm_content_groups_mmtid(),
'#mm_list_max' => 1,
'#default_value' => isset($current->mm_gid) ? [$current->mm_gid => mm_content_get_name($current->mm_gid)] : NULL,
];
$form['mm_group']['mm_exclude'] = [
'#type' => 'radios',
'#options' => [
0 => t('Add all users <b>in</b> this group'),
1 => t('Add all users <b>not in</b> this group'),
],
'#default_value' => (int) !empty($current->mm_exclude)
];
$form['actions']['submit']['#validate'][] = function($form, FormStateInterface $form_state) {
// Translate array key into single value.
$form_state->setValue('mm_gid', mm_ui_mmlist_key0($form_state->getValue('mm_gid')));
};
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*
* Hide the "View mode" select list when doing a node preview if there is only
* one option.
*/
function monster_menus_form_node_preview_form_select_alter(array &$form) {
if (count($form['view_mode']['#options']) == 1) {
$form['view_mode']['#access'] = FALSE;
}
}
/**
* Entity builder to copy $form_state values into the Node object.
*
* @param string $entity_type_id
* The entity type identifier.
* @param NodeInterface $node
* The node updated with the submitted values.
* @param array $form
* The complete form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
*
* @see \Drupal\node\NodeForm::form()
*/
function _monster_menus_node_builder($entity_type_id, NodeInterface $node, array $form, FormStateInterface $form_state) {
$fields = [
'all_values_group',
'all_values_user',
'mm_catlist',
'mm_catlist_restricted',
'mm_catlist_restricted_link',
'node-everyone',
'owner',
'publish_on',
'set_change_date',
'show_node_info',
'unpublish_on',
];
$values = $form_state->getValues();
foreach ($fields as $field) {
if (isset($values[$field])) {
if (is_a($values[$field], '\Drupal\Core\Datetime\DrupalDateTime')) {
$node->__set($field, $values[$field]->format('U'));
}
else {
$node->__set($field, $values[$field]);
}
}
else {
unset($node->$field);
}
}
}
/**
* Implements hook_preprocess_node().
*/
function monster_menus_preprocess_node(&$variables) {
/** @var NodeInterface $node */
$node = $variables['node'];
// Disable the attribution ("submitted by X on Y") line if _mm_render_pages
// sets the no_attribution flag in the node or if the node itself has
// show_attribution set and FALSE
$variables['display_submitted'] = FALSE;
$variables['submitted'] = '';
$variables['user_picture'] = '';
$show_node_info = $node->__get('show_node_info');
if (!empty($show_node_info) && $show_node_info >= 1 && $show_node_info <= 3 && empty($node->__get('no_attribution'))) {
// Unlike Drupal core, show the date of the last change, not the creation date
$date = $node->getChangedTime();
if (!empty($node->__get('set_change_date')) && $node->__get('publish_on') > 0) {
$date = $node->__get('publish_on');
}
if (!empty($date)) {
$data = ['@username' => $variables['author_name'], '@datetime' => mm_format_date($date)];
switch ($node->__get('show_node_info')) {
case 1:
$variables['submitted'] = t('Submitted by @username', $data);
break;
case 2:
$variables['submitted'] = t('Submitted on @datetime', $data);
break;
case 3:
$variables['submitted'] = t('Submitted by @username on @datetime', $data);
break;
}
$variables['display_submitted'] = TRUE;
}
}
}
// Return the first array key of an array. Useful when retrieving the first key
// from an mm_list value array.
function mm_ui_mmlist_key0($arr) {
if (is_array($arr) && $arr) {
return array_key_first($arr);
}
}
/**
* Parse the hidden data field generated by an mm_repeatlist form element into a
* set of arrays.
*
* @param string $str
* Form data to parse
* @param int $per_row
* The number of data elements per row (set)
* @return array[]
* An array of arrays. Each inner array represents one set of data entered by
* the user.
*/
function mm_ui_parse_repeatlist($str, $per_row) {
if ($per_row <= 0 || !preg_match_all('/\{:(.*?):\}/', $str, $matches, PREG_PATTERN_ORDER)) {
return [];
}
return array_chunk($matches[1], $per_row);
}
function mm_ui_validate_sometimes_required($elt, $value, FormStateInterface $form_state, $message = NULL) {
if (empty($value) && $value !== '0') {
$form_state->setError($elt, empty($message) ? t('@name field is required.', ['@name' => $elt['#title']]) : t($message));
return FALSE;
}
return TRUE;
}
/**
* Get a list of possible variable substitutions
*
* @param int $weight
* Weight of the resulting form element
* @param array $list
* Array of human-readable field names to which the help text applies
* @param array $xvars
* Optional array of system variables which are allowed
* @return array
* A form element containing the help text
*/
function mm_ui_vars_help($weight, $list, $xvars = NULL) {
$uid = Database::getConnection()->select('users', 'u')
->fields('u', ['uid'])
->condition('u.uid', 1, '>')
->range(0, 1)
->execute()->fetchField();
if (!$uid) {
$uid = \Drupal::currentUser()->id();
}
$vars = [];
if ($usr = User::load($uid)) {
foreach (array_keys($usr->getFields()) as $k) {
if (($v = $usr->get($k)->getValue()) && isset($v[0]['value']) && is_scalar($v[0]['value'])) {
$vars[$k] = '${' . $k . '}';
}
}
$rp = new \ReflectionProperty($usr::class, 'values');
$rp->setAccessible(TRUE);
foreach (array_keys($rp->getValue($usr)) as $k) {
if (isset($usr->$k) && is_scalar($usr->$k)) {
$vars[$k] = '${' . $k . '}';
}
}
}
sort($vars);
$vars = join("\n", $vars);
foreach ($list as &$l) {
$l = '<em class="placeholder">' . Html::escape($l) . '</em>';
}
$last = array_pop($list);
$list = join(', ', $list) . t(' or ') . $last;
$ret = [
'#type' => 'details',
'#title' => t('Variable substitution'),
'#weight' => $weight,
'#open' => FALSE,
'#description' => t('<p>The variables below can be inserted into the fields @list.</p><p>Variables which describe the current user:</p>',
['@list' => FilteredMarkup::create($list)]) . "<pre>$vars</pre>",
];
if ($xvars) {
sort($xvars);
$xvars = '${' . join("}\n\${", $xvars) . '}';
$ret['#description'] .= t('<p>System variables:</p><pre>@xvars</pre>', ['@xvars' => $xvars]);
}
return $ret;
}
function mm_ui_mmlist_labels() {
return [t('Move to top'), t('Move up'), t('Delete this row'), t('Move to bottom'), t('Move down'), t('Edit')];
}
/**
* Escape certain sequences for output as part of Javascript code
*
* @param $string
* The code to be escaped
* @return
* The escaped code
*/
function mm_ui_js_escape($string) {
return str_replace(
["\r", "\n", '<', '>', '&', '{', '}', '"'],
['', '', '\x3c', '\x3e', '\x26', '{', '}', '"'],
addslashes($string));
}
/**
* Implements hook_theme().
*/
function monster_menus_theme() {
return [
'mm_catlist' => [
'variables' => [
'mm_list_instance' => '',
'mm_list_tag' => '',
'mm_list_class' => '',
],
],
'tooltip' => [
'file' => 'mm_theme.inc',
'variables' => [
'text' => NULL,
'title' => NULL,
'tip' => NULL,
'html' => FALSE,
],
],
'mm_repeatlist_div' => [
'file' => 'mm_theme.inc',
'variables' => ['elt' => NULL],
],
'mm_repeatlist' => [
'variables' => [
'mm_list_instance' => '',
'mm_list_class' => '',
'mm_list_desc' => '',
'label_above_list' => '',
],
],
'mm_help_radio' => [
'render element' => 'element',
],
'mm_help_radios' => [
'render element' => 'element',
],
'mm_ui_mark_yesno' => [
'file' => 'mm_theme.inc',
'variables' => ['yes' => FALSE]
],
'mm_archive_header' => [
'file' => 'mm_theme.inc',
'variables' => [
'frequency' => NULL,
'date' => NULL,
],
],
'mm_archive' => [
'file' => 'mm_theme.inc',
'variables' => [
'list' => NULL,
'frequency' => NULL,
'this_mmtid' => NULL,
'main_mmtid' => NULL,
'archive_mmtid' => NULL,
'date' => NULL,
],
],
'mm_tree_menu' => [
'file' => 'mm_theme.inc',
'variables' => [
'menu_name' => NULL,
'items' => [],
'attributes' => [],
],
],
'mm_autocomplete_desc' => [
'variables' => [],
],
'mm_browser_bookmark_add' => [
'variables' => [
'name' => '',
'mmtid' => 0,
'base_path' => base_path(),
'mm_path' => \Drupal::service('extension.list.module')->getPath('monster_menus'),
],
],
];
}
/**
* Return "(untitled)" when a node's title is empty
*
* @param string $title
* The title
* @return string
* The original title, trimmed, or "(untitled)"
*/
function mm_ui_fix_node_title($title) {
$title = trim($title);
if (empty($title)) {
return t('(untitled)');
}
return $title;
}
/**
* Hide a node's title when it is surrounded by [brackets]
*
* @param string $title
* The title
* @return string
* The (possibly hidden) title
*/
function mm_ui_hide_node_title($title) {
return empty($title) ? '' : preg_replace('/^\[.*?\]$/', '', $title);
}
/**
* Get a list of times of day
*
* @param int $start
* If set, the starting number of minutes past midnight
* @param int $end
* If set, the ending number of minutes past midnight
* @param int $inc
* If set, the increment, in minutes, between times; the smallest supported
* number is 30 minutes
* @return array
* An array of times, indexed by the number of minutes past midnight
*/
function mm_ui_hour_list($start = NULL, $end = NULL, $inc = NULL) {
$out = [0 => t('midnight'), 30 => t('12:30 AM'), 60 => t('1:00 AM'), 90 => t('1:30 AM'), 120 => t('2:00 AM'), 150 => t('2:30 AM'), 180 => t('3:00 AM'), 210 => t('3:30 AM'), 240 => t('4:00 AM'), 270 => t('4:30 AM'), 300 => t('5:00 AM'), 330 => t('5:30 AM'), 360 => t('6:00 AM'), 390 => t('6:30 AM'), 420 => t('7:00 AM'), 450 => t('7:30 AM'), 480 => t('8:00 AM'), 510 => t('8:30 AM'), 540 => t('9:00 AM'), 570 => t('9:30 AM'), 600 => t('10:00 AM'), 630 => t('10:30 AM'), 660 => t('11:00 AM'), 690 => t('11:30 AM'), 720 => t('noon'), 750 => t('12:30 PM'), 780 => t('1:00 PM'), 810 => t('1:30 PM'), 840 => t('2:00 PM'), 870 => t('2:30 PM'), 900 => t('3:00 PM'), 930 => t('3:30 PM'), 960 => t('4:00 PM'), 990 => t('4:30 PM'), 1020 => t('5:00 PM'), 1050 => t('5:30 PM'), 1080 => t('6:00 PM'), 1110 => t('6:30 PM'), 1140 => t('7:00 PM'), 1170 => t('7:30 PM'), 1200 => t('8:00 PM'), 1230 => t('8:30 PM'), 1260 => t('9:00 PM'), 1290 => t('9:30 PM'), 1320 => t('10:00 PM'), 1350 => t('10:30 PM'), 1380 => t('11:00 PM'), 1410 => '11:30 PM'];
foreach (array_keys($out) as $key) {
if ($inc && ($key % $inc) != 0) {
unset($out[$key]);
}
if (!is_null($start) && !is_null($end) && ($key < $start || $key >= $end)) {
unset($out[$key]);
}
}
return $out;
}
/**
* Get a list of long week day names
*
* @return array
* An array of weekday names, starting with Sunday at element 0
*/
function mm_ui_day_list() {
if (function_exists('date_week_days')) return date_week_days(TRUE);
return [t('Sunday'), t('Monday'), t('Tuesday'), t('Wednesday'), t('Thursday'), t('Friday'), t('Saturday')];
}
// ****************************************************************************
// * Private functions start here
// ****************************************************************************
/**
* Validation common to copying/moving and editing/inserting a tree entry
*
* @param int $mmtid
* The tree ID of the entry being copied/movied/edited
* @param int $test_mmtid
* The tree ID of the entry's parent (when editing) or new parent (when
* copying/moving/inserting)
* @param FormStateInterface $form_state
* The form state
* @param array $form_values
* The $form_state->getValues() array
* @param bool $is_new
* Set to TRUE if the operation is creating a new entry (copy/move/insert)
* @return int
* 0 upon critical error, otherwise 1
*/
function _mm_ui_validate_entry($mmtid, $test_mmtid, FormStateInterface $form_state, $form_values, $is_new) {
$x = mm_ui_strings($is_group = mm_content_is_group($test_mmtid));
$test_tree = mm_content_get_tree($test_mmtid, [Constants::MM_GET_TREE_DEPTH => 1, Constants::MM_GET_TREE_FILTER_HIDDEN => TRUE]);
if (!$test_mmtid || count($test_tree) < ($is_new ? 1 : 2) || !$is_new && $test_tree[1]->parent != $test_tree[0]->mmtid) {
$form_state->setErrorByName('', t('Unexpected tree structure'));
return 0;
}
$name = trim($form_values['name']);
if (!\Drupal::currentUser()->hasPermission('administer all menus') && $name != '' && $name[0] == '.') {
$form_state->setErrorByName('name',
t('@thing names starting with a dot (.) are reserved for administrators.', $x));
}
$alias = empty($form_values['alias']) ? '' : trim($form_values['alias']);
if (preg_match('/^[-.\w]*$/', $alias) == 0) {
$form_state->setErrorByName('alias',
t('You have entered one or more invalid characters in the URL name.'));
}
else {
$reserved = preg_grep('{^' . preg_quote($alias) . '$}i', mm_content_reserved_aliases());
if ($reserved) {
$form_state->setErrorByName('alias',
t('The URL name %alias is not allowed. Please try changing it slightly.',
['%alias' => $alias]));
}
else if (mm_content_alias_conflicts($alias, $test_mmtid, FALSE)) {
$form_state->setErrorByName('alias',
t('The URL name %alias is not allowed at this location in the tree. Please try changing it slightly.',
['%alias' => $alias]));
}
}
array_shift($test_tree);
foreach ($test_tree as $entry) {
if ($is_new || $entry->mmtid != $mmtid) {
if (strcasecmp($entry->name, $name) == 0) {
$x['%name'] = $entry->name;
$form_state->setErrorByName('name',
t('A @thing named %name already exists at this level of the tree.', $x));
}
if (!empty($entry->alias) && $alias != '' && strcasecmp($entry->alias, $alias) == 0) {
$x['%name'] = $entry->name;
$x['%alias'] = $entry->alias;
$form_state->setErrorByName('alias',
t('The @thing named %name is already using the URL name %alias at this level of the tree.', $x));
}
}
}
return 1;
}
function _mm_ui_verify_userlist(FormStateInterface $form_state, $form_elem, $elt_name) {
if (is_array($form_elem)) {
foreach ($form_elem as $uid => $name) {
if (mm_content_uid2name($uid) === FALSE) {
$form_state->setErrorByName($elt_name, t('There is no user with uid=@uid and name=@name.', ['@uid' => $uid, '@name' => $name]));
}
}
}
elseif (is_numeric($form_elem)) {
$uid = intval($form_elem);
if (mm_content_uid2name($uid) === FALSE) {
$form_state->setErrorByName($elt_name, t('There is no user with uid=@uid.', ['@uid' => $uid]));
}
}
}
/**
* Return various versions of strings to be used in UI messages
*
* @param $is_group
* If TRUE, return strings related to groups
* @return
* An associative array of strings, suitable to be passed to t()
*/
function mm_ui_strings($is_group) {
$x['@thing'] = $is_group ? t('group') : t('page');
$x['@things'] = $is_group ? t('groups') : t('pages');
$x['@thingpos'] = $is_group ? t('group\'s') : t('page\'s');
$x['@subthing'] = $is_group ? t('sub-group') : t('sub-page');
$x['@subthings'] = $is_group ? t('sub-groups') : t('sub-pages');
return $x;
}
function _mm_ui_userlist_setup($users, &$form, $form_id, $title, $single, $desc, $other_name = '', $large_group = FALSE) {
if (!\Drupal::currentUser()->hasPermission('access user profiles')) {
$form['no-add'] = _mm_ui_no_add_user();
}
elseif (!is_null($users)) {
$form["$form_id-choose"] = [
'#type' => 'textfield',
'#title' => $single ? t('Choose the owner') : t('Add a user'),
'#autocomplete_route_name' => 'monster_menus.autocomplete',
'#description' => mm_autocomplete_desc(),
'#size' => 30,
'#maxlength' => 40,
];
$form[$form_id] = [
'#type' => 'mm_userlist',
'#description' => $desc,
'#title' => $title,
'#default_value' => $users,
'#required' => $single,
'#mm_list_autocomplete_name' => "$form_id-choose",
'#mm_list_min' => $single,
'#mm_list_max' => $single,
'#mm_list_other_name' => $other_name,
'#mm_list_initial_focus' => "$form_id-choose",
];
if ($single) {
$form[$form_id]['#mm_list_submit_on_add'] = TRUE;
}
}
else {
if ($large_group) {
$form["$form_id-add"] = [
mm_ui_add_user_subform($form, 'mmUserAddUsers', t('Add members to this group'), t('Members to add:'), t('Add members to group'), 'Drupal.mmGroupAddUser'),
];
$headers = _mm_ui_userlist_get_headers();
$output = '<table class="display" id="mm-user-datatable-' . str_replace('_', '-', $form_id) . '" width="100%">';
$output .= '<thead><tr>';
foreach ($headers as $value) {
$class = empty($value) ? ' class="no-sort"' : '';
$output .= '<th' . $class . '>' . $value . '</th>';
}
$output .= '</tr></thead>';
$output .= '<tbody><tr><td colspan="' . count($headers) . '" class="dataTables_empty">' . t('Loading data from server') . '</td></tr></tbody>';
$output .= '</table>';
$form['#attached']['library'][] = 'monster_menus/dataTables';
$form[$form_id . '-additional'] = ['#markup' => $output];
$form[$form_id . '-use-large-group'] = ['#type' => 'hidden', '#value' => 'yes', '#process' => ['mm_ui_process_large_group']];
}
else {
$form[$form_id . '-additional'] = ['#markup' => t('There are more members in this group than can be displayed. The list can only be edited by uploading a CSV file.')];
}
}
}
function mm_ui_add_user_subform(&$form, $id, $link_text, $title, $button_text, $click_func_name, $owner_uid = NULL, $owner_name = NULL) {
static $instance = 0;
$link_id = mm_ui_modal_dialog(['minWidth' => 550, 'minHeight' => 400], $form);
// To avoid ending up with nested forms, the subform must be added outside the
// main form.
$array = [
['#markup' => "<div id=\"$id-$instance\" class=\"hidden\"><div class=\"mm-add-users\">"],
'subform' => \Drupal::formBuilder()->getForm(AddGroupUsersForm::class, $instance, $link_id, $title, $button_text, $click_func_name, $owner_uid, $owner_name),
['#markup' => '</div></div>'],
];
mm_add_page_footer([
'#type' => 'html_tag',
'#tag' => 'script',
'#value' => \Drupal::service('renderer')->render($array),
'#attributes' => ['class' => 'mm-template', 'type' => 'text/template'],
]);
$result = Link::fromTextAndUrl($link_text, Url::fromRoute('<current>', [], [
'fragment' => $id . '-' . $instance++,
'external' => TRUE,
'attributes' => ['id' => $link_id, 'title' => t('Add a user')],
]))->toRenderable();
$result['#id'] = $link_id;
return $result;
}
function mm_ui_process_large_group($element, &$form_state = NULL, $form = NULL) {
if (!\Drupal::request()->request->all()) { // This will write group data even if the group fails validation, but none of the information passed seems to offer an alternative
// Copy group data to the temp table
$token = $form['mm_form_token']['#value'];
$session_id = session_id();
$gid = $form['path']['#value'];
$db = Database::getConnection();
$db->delete('mm_group_temp')
->condition('gid', $gid)
->condition('sessionid', $session_id)
->condition('token', $token)
->execute();
if (empty($form['is_new']['#value'])) {
$select = $db->select('mm_group', 'g');
$select->addField('g', 'gid');
$select->addField('g', 'uid');
$select->addExpression(':session_id', 'sessionid', [':session_id' => $session_id]);
$select->addExpression(':token', 'token', [':token' => $token]);
$select->addExpression(':expire', 'expire', [':expire' => mm_request_time() + 24 * 60 * 60]);
$select->condition('g.gid', $gid);
$db->insert('mm_group_temp')
->from($select)
->execute();
}
}
return $element;
}
/**
* Get the headers for the datatable used in large group management
*/
function _mm_ui_userlist_get_headers() {
static $headers = [];
if (empty($headers)) {
$headers = mm_module_invoke_all_array('mm_large_group_header', []);
if (empty($headers)) {
$headers = [t('Username'), ''];
}
}
return $headers;
}
function _mm_ui_is_user_home(&$item) {
if ($item->parent == mm_content_users_mmtid()) {
$item->is_user_home = TRUE;
$item->flags['limit_alias'] = '';
$item->flags['limit_delete'] = '';
$item->flags['limit_hidden'] = '';
$item->flags['limit_location'] = '';
$item->flags['limit_move'] = '';
$item->flags['limit_name'] = '';
$item->flags['limit_write'] = '';
}
}
function mm_ui_owner_desc($form, $x, $item_uid, $is_search = FALSE) {
if ($is_search || \Drupal::currentUser()->hasPermission('administer all menus')) {
$msg = t('The owner always has full access.', $x);
if (isset($form['#id']) && $form['#id'] == 'node-form') {
$msg .= ' ' . t('The owner is also publicly visible as the submitter.');
}
return [mm_ui_uid2name($item_uid), $msg, FALSE];
}
$msg = '';
if (\Drupal::currentUser()->id() != $item_uid) {
$owner = User::load($item_uid);
if ($owner) {
$x['@name'] = mm_ui_uid2name($owner->id());
$msg = t('This @thing is owned by @name, who always has full access to it.', $x);
}
}
else {
$msg = t('As the owner of this @thing, you always have full access to it.', $x);
}
return [mm_ui_uid2name($item_uid), $msg, TRUE];
}
function mm_ui_uid2name($uid, $link = FALSE) {
if (is_null($uid)) {
return t('No user');
}
if (($owner = mm_content_uid2name($uid, 'fmlu')) !== FALSE) {
if ($link) {
return Link::createFromRoute($owner, 'entity.user.canonical', ['user' => $uid])->toString();
}
return $owner;
}
return t('Unknown user #@uid', ['@uid' => $uid]);
}
function mm_ui_mm_nodelist_setup(&$mmlist, $nid, $mmtid = NULL) {
if (empty($nid)) {
$mmlist['0/0'] = '';
return;
}
$mmtids = mm_content_get_by_nid($nid);
if (!empty($mmtid) && in_array($mmtid, $mmtids)) {
$tree = mm_content_get($mmtid);
}
else {
$tree = $mmtids ? mm_content_get($mmtids[0]) : FALSE;
}
if ($tree) {
$mmlist[$tree->mmtid . '/' . $nid] = Node::load($nid)->label();
}
else {
$mmlist['0/' . $nid] = '';
}
}
function mm_ui_flags_info() {
$predefined = [];
// We need the module name, so don't use module_invoke_all()
foreach (mm_module_implements('mm_tree_flags') as $module => $callable) {
$result = call_user_func($callable);
if (isset($result) && is_array($result)) {
$predefined[$module] = $result;
}
}
ksort($predefined);
return $predefined;
}
/**
* Produce code to instantiate a modal dialog.
*
* @param array $settings
* If NULL, the most recently used dialog instance ID is returned.
*
* If the string 'init' is passed, the dialog system is initialized for future
* use by other code without actually defining a dialog.
*
* Otherwise, a new dialog is instantiated using any settings supplied. The
* settings are an associative array of values corresponding to the Options
* list found in the jquery.ui.dialog documentation:
* @see http://api.jqueryui.com/dialog
*
* These additional settings are supported:
* - fullSize (FALSE)
* If TRUE, the dialog will take up most of the browser window.
* - iframe (FALSE)
* If TRUE, the dialog will be opened within an IFRAME tag.
*
* This function is typically used when creating a link which opens a modal
* dialog. If the referring <a> tag contains an href option with a full URL,
* that location is shown within the dialog. If, instead, the href is only a
* fragment ("#something"), then that fragment is treated as a selector for
* the pre-existing DOM object to show within the dialog.
*
* To create a link which opens a modal dialog that loads its content from a
* URL use the return value from this function for the ID of the URL or link
* tag, like so:
*
* $array = [];
* $link = Link::fromTextAndUrl(
* t('Open a dialog'),
* Url::fromRoute('some/path', [], [
* 'attributes' => [
* 'id' => mm_ui_modal_dialog([], $array),
* ],
* 'external' => TRUE,
* ])
* );
* // The render array $array must now be incorporated into the output.
*
* Or, when using the Form API:
*
* $array = [];
* $array['link'] = [
* '#type' => 'link',
* '#title' => t('Open a dialog'),
* '#url' => Url::fromRoute('some/path', [], [
* 'attributes' => [
* 'id' => mm_ui_modal_dialog([], $array),
* ],
* 'external' => TRUE,
* ]),
* ];
*
* Do the same thing using a full-window iframe:
*
* $array = [];
* $array['link'] = [
* '#type' => 'link',
* '#title' => t('Open a dialog'),
* '#url' => Url::fromRoute('some/path', [], [
* 'attributes' => [
* 'id' => mm_ui_modal_dialog([
* 'iframe' => TRUE,
* 'fullSize' => TRUE
* ], $array),
* ],
* 'external' => TRUE,
* ]),
* ];
*
* To create a link which opens a modal dialog that refers to a pre-existing,
* hidden DIV with a particular ID:
*
* $array[0] = ['#markup' =>
* '<div id="my-dialog" class="hidden">This is a test.</div>'];
* $array['link'] = [
* '#type' => 'link',
* '#title' => t('Open a dialog'),
* '#url' => Url::fromRoute('<current>', [], [
* 'attributes' => [
* 'id' => mm_ui_modal_dialog([], $array),
* ],
* 'external' => TRUE,
* 'fragment' => 'my-dialog',
* ]),
* ];
* @param array &$array
* The render array to which libraries and settings will be attached.
* @return string|null
* Either the most recently used dialog instance ID (when $settings is NULL),
* or the ID of the newly-created instance.
*/
function mm_ui_modal_dialog($settings = [], &$array = []) {
static $instance = 0, $did_init;
if (is_null($settings)) {
return 'mm-dialog-' . ($instance - 1);
}
mm_add_library($array, 'modal_dialog');
if ($settings === 'init') {
if (empty($did_init)) {
$array['#attached']['drupalSettings']['MM']['useWidgetHandlerFixup'] = str_starts_with(Drupal::VERSION, '9.');
$array['#attached']['drupalSettings']['MM']['MMDialog'] = [];
$did_init = TRUE;
}
}
else {
$id = "mm-dialog-$instance";
$array['#attached']['drupalSettings']['MM']['MMDialog'][$instance++] = $settings;
return $id;
}
}
function mm_ui_js_link_no_href(array $attributes, $text, $raw_text = FALSE) {
$text_format = $raw_text ? 'text | raw' : 'text';
return [
'#type' => 'inline_template',
'#template' => '<a href="#"{{ attributes }}>{{ ' . $text_format. ' }}</a>',
'#context' => [
'attributes' => new Attribute($attributes),
'text' => $text,
]
];
}
function mm_ui_tabledrag_sample() {
$sample = [
'#type' => 'inline_template',
'#template' => '<a name="sample"{{ attributes }}><div class="handle"> </div></a>',
'#context' => [
'attributes' => new Attribute([
'class' => ['tabledrag-handle tabledrag-handle-sample'],
'title' => t('Sample of drag handle'),
]),
]
];
return FilteredMarkup::create(\Drupal::service('renderer')->renderRoot($sample));
}
/**
* Generate node permissions form elements.
*
* @param &$form
* The form element
*/
function mm_ui_node_permissions(&$form) {
$form['indiv_tbl']['#type'] = 'value';
$form['indiv_tbl']['#value'] = [
'title' => t('Individuals'),
'action' => mm_ui_add_user_subform($form, 'settings-perms-indiv-add', t('add'), t('User(s) to add to permissions'), t('Add users to permissions'), 'Drupal.MMSettingsPermsAddUsers'),
];
foreach (['indiv_tbl', 'groups_tbl'] as $type) {
$kids = [];
foreach ($form[$type] as $key => $item) {
if (is_array($item) && isset($item['#mm_delete_link'])) {
if (!isset($users)) {
$users = $item['#mm_users'];
}
if ($type == 'indiv_tbl') {
if (!isset($item_uid)) {
$item_uid = $item['#mm_owner']['uid'];
}
if (isset($form['everyone']['owner'])) {
$form['everyone']['owner']['#value'] = $item_uid;
}
if (!isset($item['#mm_owner']['show']) || !empty($item['#mm_owner']['show'])) {
[$name, $msg, $owner_readonly] = mm_ui_owner_desc($form, ['@thing' => $item['#mm_owner']['type']], $item_uid);
$kids[] = _mm_ui_perms_table_row(
'user',
'owner',
t('<span class="settings-perms-owner-prefix">Owner: </span><span class="settings-perms-owner-name">@name</span>', ['@name' => $name]),
$msg,
$owner_readonly ? NULL : mm_ui_add_user_subform($form, 'settings-perms-indiv-owner', t('change'), t('Owner'), t('Change the owner'), 'Drupal.MMSettingsPermsOwner', $item_uid, $name)
);
if (!$owner_readonly) {
$kids[] = ['#type' => 'hidden', '#name' => 'uid', '#value' => $item_uid, '#id' => "uid-$item_uid"];
}
}
if (is_array($users)) {
foreach ($users as $uid => $name) {
$obj = [
"user-w-$uid" => [
'#id' => "user-w-$uid",
'#name' => "user-w-$uid",
'#type' => 'hidden',
'#value' => $uid,
],
[
'#type' => 'item',
'#input' => FALSE,
'#markup' => $name,
],
];
$kids[] = _mm_ui_perms_table_row('user', $uid, $obj, '', !empty($form['#readonly']) ? NULL : $item['#mm_delete_link']);
}
}
if (empty($form['#readonly'])) {
// Empty row to be used when adding new users
$obj = [
'user-w-new' => [
'#attributes' => ['class' => ['user-w-new']],
'#name' => 'user-w-new',
'#type' => 'hidden',
'#value' => 0,
],
[
'#type' => 'item',
'#input' => FALSE,
'#markup' => '<div class="mm-permissions-user-new form-item"> </div>',
],
];
$kids[] = _mm_ui_perms_table_row('user', 'new', $obj, '', $item['#mm_delete_link']);
}
}
else {
if (!isset($groups)) {
$groups = $item['#mm_groups'];
}
if (is_array($groups)) {
foreach ($groups as $mmtid => $data) {
$temp_elem = $item['mm_groups_elem'];
$temp_elem[0]['#title'] = $data['name'];
$temp_elem[0][0]['#markup'] = '<div class="form-item">' . $data['members'] . '</div>';
$temp_elem[0]["group-w-$mmtid"] = [
'#id' => "group-w-$mmtid",
'#name' => "group-w-$mmtid",
'#type' => 'hidden',
'#value' => $mmtid,
];
$kids[] = _mm_ui_perms_table_row('group', $mmtid, $temp_elem, '', !empty($form['#readonly']) ? NULL : $item['#mm_delete_link']);
}
}
if (empty($form['#readonly'])) {
// Empty row to be used when adding new groups
$temp_elem = $item['mm_groups_elem'];
$temp_elem[0]['#title'] = ' ';
$temp_elem[0][0]['#attributes'] = ['class' => ['mm-permissions-group-new']];
$temp_elem[0][0]['#markup'] = '<div class="mm-permissions-group-new form-item"> </div>';
$temp_elem[0]['group-w-new'] = [
'#id' => 'group-w-new',
'#name' => 'group-w-new',
'#type' => 'hidden',
'#value' => 0,
];
unset($form['groups_tbl'][$key]['mm_groups_elem']);
$kids[] = _mm_ui_perms_table_row('group', 'new', $temp_elem, '', !empty($form['#readonly']) ? NULL : $item['#mm_delete_link']);
}
}
}
elseif (is_numeric($key)) {
$kids[] = $item;
}
else {
$kids[$key] = $item;
}
}
$form[$type] = $kids;
}
mm_ui_permissions($form);
}
function mm_ui_permissions(&$form) {
$rows = [];
foreach (Element::children($form) as $section_id) {
$form["#$section_id"] = count($rows);
$colspan = 1;
if (isset($form[$section_id]['#value']['types']) && is_array($form[$section_id]['#value']['types'])) {
$colspan = count($form[$section_id]['#value']['types']) + 1;
}
// Begin a header row with the title.
$row = [
'#attributes' => ['class' => ['mm-permissions-header-row']],
];
if (isset($form[$section_id]['#value']['title'])) {
$row[] = [
'#wrapper_attributes' => ['header' => TRUE, 'class' => ['first-col']],
'#markup' => new FormattableMarkup('<h2>@text</h2>', ['@text' => $form[$section_id]['#value']['title']]),
];
}
if (isset($form[$section_id]['#value']['types']) && is_array($form[$section_id]['#value']['types']) && !empty($form[$section_id]['#value']['headings'])) {
// Add headers above the checkboxes.
foreach ($form[$section_id]['#value']['types'] as $vals) {
$row[] = [
'#wrapper_attributes' => ['header' => TRUE],
'#markup' => new FormattableMarkup('<h4>@text</h4>', ['@text' => $vals[0]]),
];
}
// Empty header above the actions
$row[] = [
'#wrapper_attributes' => ['header' => TRUE],
'#markup' => '',
];
}
else {
// Add empty headers.
$row = array_merge($row, array_fill(0, $colspan, [
'#wrapper_attributes' => ['header' => TRUE],
'#markup' => '',
]));
}
$rows[] = $row;
// Add the data rows.
foreach (Element::children($form[$section_id]) as $row_id) {
if ($children = Element::children($form[$section_id][$row_id])) {
$row = !empty($form[$section_id][$row_id]['#mm_is_data_row']) ? ['#attributes' => ['class' => ['mm-permissions-data-row']]] : [];
// One checkbox per column
foreach ($children as $item_id) {
$item = $form[$section_id][$row_id][$item_id];
if (!isset($item['#id']) && !is_numeric($item_id)) {
$item['#id'] = $item_id;
}
$row[$item_id] = $item;
}
// Add empty cells, as needed.
$row = array_merge($row, array_fill(0, $colspan - count($children) + 1, ['#markup' => '']));
$rows[] = $row;
}
}
if (empty($form['#readonly']) && isset($form[$section_id]['#value']['action'])) {
// A link by itself on the line, most likely "add"
$rows[] = [
['#wrapper_attributes' => ['colspan' => $colspan], '#markup' => ''],
[$form[$section_id]['#value']['action']],
];
}
unset($form[$section_id]);
}
mm_static($form, 'settings_perms');
$form['#type'] = 'table';
$form['#tree'] = FALSE;
$form += $rows;
$form['#attributes'] = ['class' => ['mm-permissions']];
}
function mm_ui_settings_perms_add_group_link(&$form) {
$_mmlist_instance = &drupal_static('_mmlist_instance', 0);
$elts = \Drupal::service('element_info')->getInfo('mm_grouplist');
$popup_URL = mm_content_groups_mmtid();
return [
'#type' => 'inline_template',
'#template' => '<a href="{{ url }}" id="{{ id }}" title="{{ title }}" onclick="return Drupal.MMSettingsPermsAddGroup(this)">{{ text }}</a>',
'#context' => [
'url' => Url::fromRoute($elts['#mm_list_route'], [], ['query' => ['_path' => "$popup_URL-" . Groups::BROWSER_MODE_GROUP . "-$_mmlist_instance-" . $elts['#mm_list_enabled'] . '-' . $elts['#mm_list_selectable'] . '/' . $popup_URL]]),
'id' => mm_ui_modal_dialog(['iframe' => TRUE, 'fullSize' => TRUE, 'resizable' => FALSE, 'draggable' => FALSE, 'dialogClass' => 'mm-browser-dialog'], $form),
'title' => t('Add a group to the permissions'),
'text' => t('add'),
]
];
}
function _mm_ui_node_form_perms(&$form, $userlist, $grouplist, $everyone, $item_type, $item_uid) {
// don't allow non-admins to permit everyone for write
$allow_ev = \Drupal::currentUser()->hasPermission('administer all menus');
_mm_ui_form_array_merge($form, 'settings_perms', [
'#type' => 'details',
'#title' => t('Who can edit or delete this content'),
'#group' => 'advanced',
'#weight' => 121,
]);
$form['settings_perms']['table']['#type'] = 'table';
$form['settings_perms']['table']['#weight'] = 21;
$form['settings_perms']['table']['#perms'] = [
'allow_everyone' => $allow_ev,
'everyone' => $everyone,
'users' => $userlist,
'groups' => $grouplist,
'owner' => $item_uid,
];
if ($allow_ev) {
$form['settings_perms']['table']['everyone'] = [
'#type' => 'value',
'#value' => [
'title' => t('Everyone'),
'headings' => TRUE,
],
];
$checkbox = [
'node-everyone' => [
'#type' => 'checkbox',
'#title' => t('Everyone can edit or delete this content'),
'#default_value' => $everyone,
],
'owner' => [
'#type' => 'hidden',
'#default_value' => $item_uid,
],
];
$form['settings_perms']['table']['everyone'][] = _mm_ui_perms_table_row('', 'others_w', $checkbox, '');
}
$form['settings_perms']['table']['indiv_tbl'] = [];
if (empty($is_search)) {
$form['settings_perms']['table']['indiv_tbl'][] = [
'#type' => 'markup',
'#mm_delete_link' => mm_ui_js_link_no_href(['title' => t('Remove this user'), 'onclick' => 'return Drupal.MMSettingsPermsDelete(this)'], t('delete')),
'#mm_users' => $userlist,
'#mm_owner' => [
'type' => $item_type,
'uid' => $item_uid,
],
];
$form['settings_perms']['all_values_user'] = [
'#type' => 'hidden',
'#attributes' => ['class' => 'mm-permissions-all-values-user'],
'#default_value' => $userlist ? Constants::MM_PERMS_WRITE . implode(Constants::MM_PERMS_WRITE, array_keys($userlist)) : '', // default value, in case JS is disabled
];
}
$form['settings_perms']['table']['groups_tbl'] = [
'#type' => 'value',
'#value' => [
'title' => t('Groups'),
'action' => mm_ui_settings_perms_add_group_link($form),
]
];
if (empty($is_search)) {
$elem = [
[
'#type' => 'details',
'#open' => FALSE,
]
];
$form['settings_perms']['table']['groups_tbl'][] = [
'#type' => 'markup',
'#mm_delete_link' => mm_ui_js_link_no_href(['title' => t('Remove this group'), 'onclick' => 'return Drupal.MMSettingsPermsDelete(this)'], t('delete')),
'#mm_groups' => $grouplist,
'mm_groups_elem' => $elem,
];
$form['settings_perms']['all_values_group'] = [
'#type' => 'hidden',
'#attributes' => ['class' => 'mm-permissions-all-values-group'],
'#default_value' => $grouplist ? Constants::MM_PERMS_WRITE . implode(Constants::MM_PERMS_WRITE, array_keys($grouplist)) : '', // default value, in case JS is disabled
];
}
mm_ui_node_permissions($form['settings_perms']['table']);
}
function _mm_ui_perms_table_row($elem_name, $elem_id, $name, $msg = '', $action = NULL, $types = [], $x = NULL, $checks = []) {
$out = ['#mm_is_data_row' => is_numeric($elem_id)];
$out[] = is_array($name) ? $name : [
'#type' => 'item',
'#input' => FALSE,
'#markup' => "<div class=\"mm-permissions-$elem_name-$elem_id\">$name</div>",
'#description' => $msg,
'#description_display' => 'after',
];
$chk = 0;
foreach (array_keys($types) as $mode) {
if (!is_bool($checks[$chk])) {
$out[] = [];
}
else {
$att = ['title' => t($types[$mode][1], $x)];
if ($checks[$chk + 1]) {
$att['class'] = ['mm-permissions-disabled'];
}
$out["$elem_name-$mode-$elem_id"] = [
'#type' => 'checkbox',
'#default_value' => $checks[$chk],
'#disabled' => $checks[$chk + 1],
'#attributes' => $att,
'#name' => "$elem_name-$mode-$elem_id",
];
}
$chk += 2;
}
$out[] = is_string($action) ? ['#type' => 'item', '#input' => FALSE, '#markup' => $action] : $action;
return $out;
}
function _mm_ui_delete_node_groups(NodeInterface $node, $everyone) {
$db = Database::getConnection();
$txn = $db->startTransaction();
try {
// ad-hoc and (maybe) "everyone"
//
// This is happening within a transaction, so it's OK (and faster) to use
// separate queries.
$gids = mm_retry_query('SELECT gid FROM {mm_node_write} WHERE nid = :nid AND gid '. ($everyone ? '<= 0' : '< 0'), [':nid' => $node->id()])->fetchCol();
if ($gids) {
mm_retry_query($db->delete('mm_group')
->condition('gid', $gids, 'IN'));
mm_retry_query($db->delete('mm_node_write')
->condition('gid', $gids, 'IN'));
}
// everything else
$delete = $db->delete('mm_node_write')
->condition('nid', $node->id());
if ($everyone)
$delete->condition('gid', 0, '<>');
mm_retry_query($delete);
}
catch (\Exception $e) {
$txn->rollBack();
// Repeat the exception, but with the location below.
throw new \Exception($e->getMessage());
}
}
function _mm_ui_recycle_page_list($mmtids, &$names, &$msg, $can = FALSE) {
$names = [];
foreach (mm_content_get($mmtids) as $tree) {
$link = Link::fromTextAndUrl(mm_content_get_name($tree), mm_content_get_mmtid_url($tree->mmtid))->toString();
if ($can) {
$perms = mm_content_user_can($tree->mmtid);
if (!$perms[Constants::MM_PERMS_APPLY]) {
$msg = t('You do not have permission to restore this content to the page it originally came from, @link.', ['@link' => $link]);
return FALSE;
}
if ($perms[Constants::MM_PERMS_IS_RECYCLED]) {
$msg = t('This content cannot be restored because the page it originally came from, @link, is also in the recycle bin. You must restore that page first.', ['@link' => $link]);
return FALSE;
}
}
$names[] = $link;
}
if (!$names) {
$msg = t('This content is not associated with a page. It will be visible only by its direct web address.<p>Are you sure you want to restore it?</p>');
}
elseif (count($names) == 1) {
$msg = t('Are you sure you want to restore this content to the page @link?', ['@link' => $names[0]]);
}
else {
$msg = t('Are you sure you want to restore this content to the following pages: @pages', ['@pages' => FilteredMarkup::create(implode(', ', $names))]);
}
return TRUE;
}
function _mm_ui_node_info_values(&$form) {
mm_add_js_setting($form, 'mmNodeInfo', [t('none'), t('name'), t('date'), t('name/date')]);
return [
0 => t('(none)'),
1 => t('Submitted by [username]'),
2 => t('Submitted on [date]'),
3 => t('Submitted by [username] on [date]'),
];
}
function _mm_ui_comment_write_setting_values() {
return [
t('Disabled: No comments allowed'),
t('Read-only: Existing comments can be read, no new ones can be added'),
t('Read/Write: All logged-in users can add comments')];
}
function _mm_ui_comment_read_setting_values($blank) {
$out = ['' => $blank];
foreach (mm_get_setting('comments.readable_labels') as $label) {
$out[$label['perm']] = $label['desc'];
}
return $out;
}
// Set form arrays in such a way that content added beforehand in other modules'
// hook_form_alter() is preserved
function _mm_ui_form_array_merge(&$form, $element, $value) {
$form[$element] = isset($form[$element]) && is_array($form[$element]) ? array_merge($value, $form[$element]) : $value;
}
function _mm_ui_form_parse_perms(FormStateInterface $form_state, $form_vals, $validate, $instance_suffix = '') {
$form_vals = $form_vals ?: (object) $form_state->getValues();
$limit_write_not_admin = isset($form_vals->limit_write_not_admin);
$groups = [];
if (!empty($form_vals->{"all_values_group$instance_suffix"})) {
preg_match_all('/(\w)(\d+)/', $form_vals->{"all_values_group$instance_suffix"}, $matches);
$i = 0;
foreach ($matches[1] as $short) {
if (!$limit_write_not_admin || $short != Constants::MM_PERMS_WRITE) { // can't use MM_PERMS_WRITE if limit_write is set
if ($group = mm_content_get(intval($matches[2][$i]))) {
$name = mm_content_get_name($group);
if ($validate) {
if (!mm_content_user_can($group->mmtid, Constants::MM_PERMS_APPLY))
$form_state->setErrorByName('', t('You do not have permission to use the group %grp.', ['%grp' => $name]));
$groups[$short][] = $group->mmtid;
}
else {
$groups[$group->mmtid]['modes'][] = $short;
$groups[$group->mmtid]['name'] = $name;
if (!isset($groups[$group->mmtid]['members'])) {
$groups[$group->mmtid]['members'] = mm_content_get_users_in_group($group->mmtid, '<br />', FALSE, 20, TRUE);
}
}
}
}
$i++;
}
}
$users = [];
if (!empty($form_vals->{"all_values_user$instance_suffix"})) {
preg_match_all('/(\w)(\d+)/', $form_vals->{"all_values_user$instance_suffix"}, $matches);
$i = 0;
foreach ($matches[1] as $short) {
if (!$limit_write_not_admin || $short != Constants::MM_PERMS_WRITE) { // can't use MM_PERMS_WRITE if limit_write is set
if (User::load($uid = intval($matches[2][$i]))) {
if ($validate) $users[$short][] = $uid;
else {
$users[$uid]['modes'][] = $short;
$users[$uid]['name'] = mm_content_uid2name($uid);
}
}
}
$i++;
}
}
if ($limit_write_not_admin) {
// Replace data protected by limit_write flag
$db = Database::getConnection();
$select = $db->select('mm_tree', 't');
$select->join('mm_tree_access', 'a', 'a.mmtid = t.mmtid');
$select->join('mm_tree', 't2', 't2.mmtid = a.gid');
$select->fields('a', ['gid']);
$select->addExpression('t2.mmtid', 't2_mmtid');
$select->condition('a.mmtid', $form_vals->path)
->condition('a.gid', 0, '>=')
->condition('a.mode', Constants::MM_PERMS_WRITE);
$result = $select->execute();
foreach ($result as $r) {
$name = mm_content_get_name($r->t2_mmtid);
if ($validate) {
$groups[Constants::MM_PERMS_WRITE][] = $r->gid;
}
else {
$groups[$r->gid]['modes'][] = Constants::MM_PERMS_WRITE;
$groups[$r->gid]['name'] = $name;
if (!isset($groups[$r->gid]['members'])) {
$groups[$r->gid]['members'] = mm_content_get_users_in_group($r->gid, '<br />', FALSE, 20, TRUE);
}
}
}
$gids = [];
$select = $db->select('mm_tree', 't');
$select->join('mm_tree_access', 'a', 'a.mmtid = t.mmtid');
$select->fields('a', ['gid'])
->condition('a.mmtid', $form_vals->path)
->condition('a.gid', 0, '<')
->condition('a.mode', Constants::MM_PERMS_WRITE);
$result = $select->execute();
foreach ($result as $r) {
$gids[] = $r->gid;
}
if ($gids) {
$users_in_groups = mm_content_get_users_in_group($gids, NULL, FALSE, 0);
if (!is_null($users_in_groups)) {
foreach ($users_in_groups as $uid => $usr) {
if (is_numeric($uid) && $uid >= 0) {
if ($validate) $users[Constants::MM_PERMS_WRITE][] = $uid;
else {
$users[$uid]['modes'][] = Constants::MM_PERMS_WRITE;
$users[$uid]['name'] = $usr;
}
}
}
}
}
}
$default_modes = [];
foreach ([Constants::MM_PERMS_WRITE, Constants::MM_PERMS_SUB, Constants::MM_PERMS_APPLY, Constants::MM_PERMS_READ] as $mode) {
if (!empty($form_vals->{"group-$mode-everyone$instance_suffix"})) {
$default_modes[] = $mode;
}
}
return [$groups, $users, $default_modes];
}
function mm_ui_is_search() {
// Some things are done differently when forms are being built for the
// search/replace feature. Assume that if _mmsr_vars is set, it must be
// because the search form elements are being generated.
return drupal_static('mm_building_search_form') !== NULL;
}
function _mm_ui_add_summary_js(&$form, $id = '') {
// Do not add code if the search interface is being generated.
if (mm_ui_is_search()) return;
if ($id) {
mm_static($form, $id . '_summary');
}
// else {
// mm_add_js_setting($form, 'summaryFuncs', []);
// }
}
function _mm_ui_no_add_user() {
return ['#markup' => t('<p>You do not have permission to choose users.</p>')];
}
