From a334457968ee7b1f0ae637b20937d6b4100004f5 Mon Sep 17 00:00:00 2001
From: dench0 <dench0@896504.no-reply.drupal.org>
Date: Fri, 8 Jan 2021 16:36:15 +1100
Subject: [PATCH] Issue #3188833 by elgandoz, dench0: Add a visual design for
 unpublished/disabled items

---
 css/Plugin/jstree/hm.jstree.css               |  10 ++
 hierarchy_manager.libraries.yml               |  15 ++-
 src/Controller/HmMenuController.php           | 109 +++++++++---------
 src/Controller/HmTaxonomyController.php       |  10 +-
 .../HmDisplayPlugin/HmDisplayJstree.php       |  30 +++--
 src/PluginTypeManager.php                     |  13 ++-
 6 files changed, 107 insertions(+), 80 deletions(-)
 create mode 100644 css/Plugin/jstree/hm.jstree.css

diff --git a/css/Plugin/jstree/hm.jstree.css b/css/Plugin/jstree/hm.jstree.css
new file mode 100644
index 0000000..90ceca9
--- /dev/null
+++ b/css/Plugin/jstree/hm.jstree.css
@@ -0,0 +1,10 @@
+
+/* HM Tree item status (unpublished/disabled) */
+.jstree-default .jstree-node.hm-tree-node-disabled {
+  color: grey;
+}
+
+/* HM menu labeling */
+.hm-tree-label {
+  font-style: italic;
+}
diff --git a/hierarchy_manager.libraries.yml b/hierarchy_manager.libraries.yml
index a160505..a29acda 100644
--- a/hierarchy_manager.libraries.yml
+++ b/hierarchy_manager.libraries.yml
@@ -3,10 +3,13 @@
 feature.hm.jstree:
   js:
     js/Plugin/jstree/hm.jstree.js: {}
+  css:
+    theme:
+      css/Plugin/jstree/hm.jstree.css: {}
   dependencies:
     - hierarchy_manager/libraries.jquery.jstree
     - core/drupalSettings
-    
+
 feature.hm.jsoneditor:
   js:
     js/Plugin/jsoneditor/hm.jsoneditor.js: {}
@@ -28,7 +31,7 @@ libraries.jquery.jstree:
     /libraries/jquery.jstree/3.3.8/jstree.min.js: {minified: true}
   dependencies:
     - core/jquery
-    
+
 libraries.jquery.jstree.default:
   remote: https://github.com/vakata/jstree
   version: '3.3.8'
@@ -41,7 +44,7 @@ libraries.jquery.jstree.default:
   css:
     component:
       /libraries/jquery.jstree/3.3.8/themes/default/style.min.css: {}
-    
+
 libraries.jquery.jstree.default-dark:
   remote: https://github.com/vakata/jstree
   version: '3.3.8'
@@ -54,7 +57,7 @@ libraries.jquery.jstree.default-dark:
   css:
     component:
       /libraries/jquery.jstree/3.3.8/themes/default-dark/style.min.css: {}
-      
+
 libraries.jsoneditor:
   remote: https://github.com/josdejong/jsoneditor
   version: '7.0.4'
@@ -66,7 +69,7 @@ libraries.jsoneditor:
     https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/7.0.4/
   js:
     /libraries/jsoneditor/7.0.4/jsoneditor.min.js: {minified: true}
-    
+
 libraries.jsoneditor.default-theme:
   remote: https://github.com/josdejong/jsoneditor
   version: '7.0.4'
@@ -78,4 +81,4 @@ libraries.jsoneditor.default-theme:
     https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/7.0.4/
   css:
     component:
-      /libraries/jsoneditor/7.0.4/jsoneditor.min.css: {minified: true}
\ No newline at end of file
+      /libraries/jsoneditor/7.0.4/jsoneditor.min.css: {minified: true}
diff --git a/src/Controller/HmMenuController.php b/src/Controller/HmMenuController.php
index 77a7b56..e44a4d8 100644
--- a/src/Controller/HmMenuController.php
+++ b/src/Controller/HmMenuController.php
@@ -15,53 +15,53 @@ use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpFoundation\JsonResponse;
 
 class HmMenuController extends ControllerBase {
-  
+
   /**
    * CSRF Token.
    *
    * @var \Drupal\Core\Access\CsrfTokenGenerator
    */
   protected $csrfToken;
-  
+
   /**
    * The menu_link_content storage handler.
    *
    * @var \Drupal\menu_link_content\MenuLinkContentStorageInterface
    */
   protected $storageController;
-  
+
   /**
    * The hierarchy manager plugin type manager.
    *
    * @var \Drupal\hierarchy_manager\PluginTypeManager
    */
   protected $hmPluginTypeManager;
-  
+
   /**
    * The menu tree service.
    *
    * @var \Drupal\Core\Menu\MenuLinkTreeInterface
    */
   protected $menuTree;
-  
+
   /**
    * The menu tree array.
    *
    * @var array
    */
   protected $overviewTree = [];
-  
+
   /**
    * The menu link manager.
    *
    * @var \Drupal\Core\Menu\MenuLinkManagerInterface
    */
   protected $menuLinkManager;
-  
+
   /**
    * {@inheritdoc}
    */
-  public function __construct(CsrfTokenGenerator $csrfToken, EntityTypeManagerInterface $entity_type_manager, $plugin_type_manager, MenuLinkTreeInterface $menu_tree, MenuLinkManagerInterface $menu_link_manager) {    
+  public function __construct(CsrfTokenGenerator $csrfToken, EntityTypeManagerInterface $entity_type_manager, $plugin_type_manager, MenuLinkTreeInterface $menu_tree, MenuLinkManagerInterface $menu_link_manager) {
     $this->csrfToken = $csrfToken;
     $this->entityTypeManager = $entity_type_manager;
     $this->storageController = $entity_type_manager->getStorage('menu_link_content');
@@ -69,7 +69,7 @@ class HmMenuController extends ControllerBase {
     $this->menuTree = $menu_tree;
     $this->menuLinkManager = $menu_link_manager;
   }
-  
+
   /**
    * {@inheritdoc}
    */
@@ -82,7 +82,7 @@ class HmMenuController extends ControllerBase {
         $container->get('plugin.manager.menu.link')
         );
   }
-  
+
   /**
    * Callback for menu tree json.
    *
@@ -94,42 +94,42 @@ class HmMenuController extends ControllerBase {
   public function menuTreeJson(Request $request, string $mid) {
     // Access token.
     $token = $request->get('token');
-    
+
     if (empty($token) || !$this->csrfToken->validate($token, $mid)) {
       return new Response($this->t('Access denied!'));
     }
-    
+
     $parent = $request->get('parent');
     $depth = $request->get('depth');
     $destination = $request->get('destination');
-    
+
     if (empty($depth)) {
       $depth = 0;
     }
     else {
       $depth = intval($depth);
     }
-    
+
     if (empty($parent)) {
       $parent = '';
     }
-    
+
     // We indicate that a menu administrator is running the menu access check.
     $request->attributes->set('_menu_admin', TRUE);
-    
+
     $tree = $this->loadMenuTree($mid, $parent, $depth, $destination);
-    
+
     // menu access check done.
     $request->attributes->set('_menu_admin', FALSE);
-    
+
     if ($tree) {
       // Display plugin instance.
       $display_plugin = $this->getDisplayPlugin();
-      
+
       if (empty($display_plugin)) {
         return new JsonResponse(['result' => 'Display profile has not been set up.']);
       }
-      
+
       if (method_exists($display_plugin, 'treeData')) {
         // Transform the tree data to the structure
         // that display plugin accepts.
@@ -138,13 +138,13 @@ class HmMenuController extends ControllerBase {
       else {
         $tree_data = $tree;
       }
-      
+
       return new JsonResponse($tree_data);
     }
-    
+
     return new JsonResponse([]);
   }
-  
+
   /**
    * Callback for taxonomy tree json.
    *
@@ -159,7 +159,7 @@ class HmMenuController extends ControllerBase {
     if (empty($token) || !$this->csrfToken->validate($token, $mid)) {
       return new Response($this->t('Access denied!'));
     }
-    
+
     $target_position = $request->get('target');
     $parent = $request->get('parent');
     $updated_links = $request->get('keys');
@@ -167,7 +167,7 @@ class HmMenuController extends ControllerBase {
     $before = $request->get('before');
     $all_siblings = [];
     $insert_after = TRUE;
-    
+
     if (is_array($updated_links) && !empty($updated_links)) {
       if (empty($parent)) {
         // Root is the parent.
@@ -177,7 +177,7 @@ class HmMenuController extends ControllerBase {
       else {
         // All children menu links (depth = 1).
         $parent_links = $this->loadMenuLinkObjs($mid, $parent, 1);
-      }  
+      }
       // In order to make room for menu links inserted,
       // we need to move all children links forward,
       // and work out the weight for links inserted.
@@ -204,40 +204,40 @@ class HmMenuController extends ControllerBase {
           if ($position++ == $target_position && $link_id !== $before) {
             $insert_after = FALSE;
           }
-          
+
           $all_siblings[$link_id] = (int) $link->getWeight();
         }
       }
       else {
         // The parent link doesn't have children.
-        
+
       }
-      
+
       $new_hierarchy = $this->hmPluginTypeManager->updateHierarchy($target_position, $all_siblings, $updated_links, $insert_after);
       // Update all links need to update.
       foreach ($new_hierarchy as $link_id => $link_weight) {
         $this->menuLinkManager->updateDefinition($link_id, ['weight' => $link_weight, 'parent' => $parent]);
       }
-      
+
       return new JsonResponse(['result' => 'success']);
     }
-    
+
     return new JsonResponse(['result' => 'fail']);
   }
-  
+
   /**
    * Get a display plugin instance.
-   * 
+   *
    * @return NULL|object
    */
   protected function getDisplayPlugin() {
     $display_profile = $this->hmPluginTypeManager->getDisplayProfile('hm_setup_menu');
     return $this->hmPluginTypeManager->getDisplayPluginInstance($display_profile);
   }
-  
+
   /**
    * Load menu links into one array.
-   * 
+   *
    * @param string $mid
    *   The menu ID.
    * @param string $parent
@@ -257,15 +257,17 @@ class HmMenuController extends ControllerBase {
         $element['url'] = $element['url'] . '?destination=' . $destination;
       }
       $links[] = $this->hmPluginTypeManager->buildHierarchyItem(
-          $element['id'],
-          $element['title'],
-          $element['parent'],
-          $element['url']);
+        $element['id'],
+        $element['title'],
+        $element['parent'],
+        $element['url'],
+        $element['status']
+      );
     }
-    
+
     return $links;
   }
-  
+
   /**
    * Load menu links into one array.
    *
@@ -291,10 +293,10 @@ class HmMenuController extends ControllerBase {
       ['callable' => 'menu.default_tree_manipulators:checkAccess'],
       ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
     ];
- 
+
     return $tree = $this->menuTree->transform($tree, $manipulators);
   }
-  
+
   /**
    * Recursive helper function for loadMenuTree().
    *
@@ -308,33 +310,34 @@ class HmMenuController extends ControllerBase {
 //    $tree_access_cacheability = new CacheableMetadata();
     foreach ($tree as $element) {
 //      $tree_access_cacheability = $tree_access_cacheability->merge(CacheableMetadata::createFromObject($element->access));
-      
+
       // Only load accessible links.
       if (!$element->access->isAllowed()) {
         continue;
       }
-      
+
       /** @var \Drupal\Core\Menu\MenuLinkInterface $link */
       $link = $element->link;
       if ($link) {
-        // The id consistes of plugin ID and link ID. 
+        // The id consistes of plugin ID and link ID.
         $id = $link->getPluginId();
         $this->overviewTree[$id]['id'] = $id;
+        $this->overviewTree[$id]['status'] = $link->isEnabled();
         if (!$link->isEnabled()) {
-          $this->overviewTree[$id]['title'] = '(' . $this->t('disabled') . ')' . $link->getTitle();
+          $this->overviewTree[$id]['title'] = $link->getTitle() . ' <span class="hm-tree-label hm-tree-label--disabled">(' . $this->t('disabled') . ')</span>';
         }
         // @todo Remove this in https://www.drupal.org/node/2568785.
         elseif ($id === 'user.logout') {
-          $this->overviewTree[$id]['title'] = ' (' . $this->t('<q>Log in</q> for anonymous users') . ')' . $link->getTitle();
+          $this->overviewTree[$id]['title'] = $link->getTitle() . ' <span class="hm-tree-label hm-tree-label--login">(' . $this->t('<q>Log in</q> for anonymous users') . ')</span>';
         }
         // @todo Remove this in https://www.drupal.org/node/2568785.
         elseif (($url = $link->getUrlObject()) && $url->isRouted() && $url->getRouteName() == 'user.page') {
-          $this->overviewTree[$id]['title'] = ' (' . $this->t('logged in users only') . ')' . $link->getTitle();
+          $this->overviewTree[$id]['title'] = $link->getTitle() . ' <span class="hm-tree-label hm-tree-label--logged-only">(' . $this->t('logged in users only') . ')</span>';
         }
         else {
           $this->overviewTree[$id]['title'] = $link->getTitle();
         }
-        
+
         $this->overviewTree[$id]['parent'] = $link->getParent();
         // Build the edit url.
         // Allow for a custom edit link per plugin.
@@ -347,16 +350,16 @@ class HmMenuController extends ControllerBase {
           $this->overviewTree[$id]['url'] = Url::fromRoute('menu_ui.link_edit', ['menu_link_plugin' => $link->getPluginId()])->toString();
         }
       }
-      
+
       if ($element->subtree) {
         $this->buildMenuLinkArray($element->subtree);
       }
     }
-    
+
  /*    $tree_access_cacheability
     ->merge(CacheableMetadata::createFromRenderArray($this->overviewTree))
     ->applyTo($form); */
-    
+
     return $this->overviewTree;
   }
 }
diff --git a/src/Controller/HmTaxonomyController.php b/src/Controller/HmTaxonomyController.php
index 7d28ece..24116f4 100644
--- a/src/Controller/HmTaxonomyController.php
+++ b/src/Controller/HmTaxonomyController.php
@@ -104,10 +104,12 @@ class HmTaxonomyController extends ControllerBase {
             }
 
             $term_array[] = $this->hmPluginTypeManager->buildHierarchyItem(
-                $term->id(), 
-                $term->label(), 
-                $term->parents[0], 
-                $url);
+              $term->id(), 
+              $term->label(), 
+              $term->parents[0], 
+              $url,
+              $term->isPublished()
+            );
           }
         }
       }
diff --git a/src/Plugin/HmDisplayPlugin/HmDisplayJstree.php b/src/Plugin/HmDisplayPlugin/HmDisplayJstree.php
index 3b59017..e91b0e0 100644
--- a/src/Plugin/HmDisplayPlugin/HmDisplayJstree.php
+++ b/src/Plugin/HmDisplayPlugin/HmDisplayJstree.php
@@ -18,7 +18,7 @@ use Drupal\hierarchy_manager\Plugin\HmDisplayPluginBase;
  */
 class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInterface {
   use StringTranslationTrait;
-  
+
   /*
    * Build the tree form.
    */
@@ -28,17 +28,17 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte
         $parent_formObj = $form_state->getFormObject();
         $parent_id = $parent_formObj->getFormId();
       }
-      
+
       // The jsTree default theme.
       $theme = 'default';
-      
+
       if (!empty($options)) {
         $jsonObj = json_decode($options);
         if (isset($jsonObj->theme) && isset($jsonObj->theme->name)) {
           $theme = $jsonObj->theme->name;
         }
       }
-    
+
       // Search input.
       $form['search'] = [
         '#type' => 'textfield',
@@ -56,7 +56,7 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte
         '#size' => 60,
         '#maxlength' => 128,
       ];
-      
+
       $form['jstree'] = [
         '#type' => 'html_tag',
         '#suffix' => '<div class="description">' . $this->t('Click a tree node to edit it.') . '<br>' . $this->t('The tree node is draggable and droppable') . '</div>',
@@ -73,22 +73,22 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte
           'url-update' => $url_update,
         ],
       ];
-      
+
       $form['#attached']['library'][] = 'hierarchy_manager/libraries.jquery.jstree.' . $theme;
       $form['#attached']['library'][] = 'hierarchy_manager/feature.hm.jstree';
       $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
     }
-    
+
     return $form;
-    
+
   }
-  
+
   /**
    * Build the data array that JS library accepts.
    */
   public function treeData(array $data) {
     $jstree_data = [];
-    
+
     // The array key of jsTree is different from the data source.
     // So we need to translate them.
     foreach ($data as $tree_node) {
@@ -98,10 +98,16 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte
         $jstree_node['parent'] = '#';
       }
 
+      if (!$tree_node['status']) {
+        $jstree_node['li_attr'] = [
+          'class' => 'hm-tree-node-disabled',
+        ];
+      }
+
       $dialog_options = [
         'minWidth' => '300',
         'width' => '960',
-        'title' => $this->t('Edit') . ' ' . $tree_node['text'],
+        'title' => $this->t('Edit') . ' ' . preg_replace('~<span(.*?)</span>~Usi', '', $tree_node['text']),
       ];
       // Custom data
       $jstree_node['a_attr'] = [
@@ -114,7 +120,7 @@ class HmDisplayJstree extends HmDisplayPluginBase implements HmDisplayPluginInte
       // Add this node into the data array.
       $jstree_data[] = $jstree_node;
     }
-    
+
     return $jstree_data;
   }
 }
diff --git a/src/PluginTypeManager.php b/src/PluginTypeManager.php
index 0f6f891..fb277d3 100644
--- a/src/PluginTypeManager.php
+++ b/src/PluginTypeManager.php
@@ -50,16 +50,19 @@ class PluginTypeManager {
    *   Parent id of the item.
    * @param string $edit_url
    *   The URL where to edit this item.
+   * @param boolean $status
+   *   The item status.
    * @return array
    *   The hierarchy item array.
    */
-  public function buildHierarchyItem($id, $label, $parent, $edit_url) {
+  public function buildHierarchyItem($id, $label, $parent, $edit_url, $status = TRUE) {
     return 
     [
-    'id' => $id,
-    'text' => $label,
-    'parent' => $parent,
-    'edit_url' => $edit_url,
+      'id' => $id,
+      'text' => $label,
+      'parent' => $parent,
+      'edit_url' => $edit_url,
+      'status' => $status
     ];
   }
   
-- 
GitLab