Skip to content

Commit

Permalink
Migrate KAM smartmenus to core
Browse files Browse the repository at this point in the history
  • Loading branch information
colemanw committed Feb 14, 2019
1 parent 6f72467 commit 7062737
Show file tree
Hide file tree
Showing 29 changed files with 1,422 additions and 459 deletions.
1 change: 1 addition & 0 deletions CRM/Admin/Form/Preferences/Display.php
Expand Up @@ -51,6 +51,7 @@ class CRM_Admin_Form_Preferences_Display extends CRM_Admin_Form_Preferences {
'ajaxPopupsEnabled' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'display_name_format' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'sort_name_format' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
'menubar_position' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
);

/**
Expand Down
81 changes: 61 additions & 20 deletions CRM/Admin/Page/AJAX.php
Expand Up @@ -37,35 +37,76 @@
class CRM_Admin_Page_AJAX {

/**
* CRM-12337 Output navigation menu as executable javascript.
*
* @see smarty_function_crmNavigationMenu
* Outputs menubar data (json format) for the current user.
*/
public static function getNavigationMenu() {
$contactID = CRM_Core_Session::singleton()->get('userID');
if ($contactID) {
CRM_Core_Page_AJAX::setJsHeaders();
$smarty = CRM_Core_Smarty::singleton();
$smarty->assign('quicksearchOptions', self::getSearchOptions());
print $smarty->fetchWith('CRM/common/navigation.js.tpl', array(
'navigation' => CRM_Core_BAO_Navigation::createNavigation(),
));
public static function navMenu() {
if (CRM_Core_Session::getLoggedInContactID()) {

$menu = CRM_Core_BAO_Navigation::buildNavigationTree();
CRM_Core_BAO_Navigation::buildHomeMenu($menu);
CRM_Utils_Hook::navigationMenu($menu);
CRM_Core_BAO_Navigation::fixNavigationMenu($menu);
CRM_Core_BAO_Navigation::orderByWeight($menu);
CRM_Core_BAO_Navigation::filterByPermission($menu);
self::formatMenuItems($menu);

$output = [
'menu' => $menu,
'search' => CRM_Utils_Array::makeNonAssociative(self::getSearchOptions()),
];
// Encourage browsers to cache for a long time - 1 year
$ttl = 60 * 60 * 24 * 364;
CRM_Utils_System::setHttpHeader('Expires', gmdate('D, d M Y H:i:s \G\M\T', time() + $ttl));
CRM_Utils_System::setHttpHeader('Cache-Control', "max-age=$ttl, public");
CRM_Utils_System::setHttpHeader('Content-Type', 'application/json');
print (json_encode($output));
}
CRM_Utils_System::civiExit();
}

/**
* @param array $menu
*/
public static function formatMenuItems(&$menu) {
foreach ($menu as $key => &$item) {
$props = $item['attributes'];
unset($item['attributes']);
if (!empty($props['separator'])) {
$item['separator'] = ($props['separator'] == 1 ? 'bottom' : 'top');
}
if (!empty($props['icon'])) {
$item['icon'] = $props['icon'];
}
if (!empty($props['attr'])) {
$item['attr'] = $props['attr'];
}
if (!empty($props['url'])) {
$item['url'] = CRM_Utils_System::evalUrl(CRM_Core_BAO_Navigation::makeFullyFormedUrl($props['url']));
}
if (!empty($props['label'])) {
$item['label'] = ts($props['label'], ['context' => 'menu']);
}
$item['name'] = !empty($props['name']) ? $props['name'] : CRM_Utils_String::munge(CRM_Utils_Array::value('label', $props));
if (!empty($item['child'])) {
self::formatMenuItems($item['child']);
}
}
$menu = array_values($menu);
}

public static function getSearchOptions() {
$searchOptions = Civi::settings()->get('quicksearch_options');
$searchOptions[] = 'sort_name';
$searchOptions = array_intersect_key(CRM_Core_SelectValues::quicksearchOptions(), array_flip($searchOptions));
foreach ($searchOptions as $key => $label) {
$searchOptions = array_merge(['sort_name'], Civi::settings()->get('quicksearch_options'));
$labels = CRM_Core_SelectValues::quicksearchOptions();
$result = [];
foreach ($searchOptions as $key) {
$label = $labels[$key];
if (strpos($key, 'custom_') === 0) {
unset($searchOptions[$key]);
$id = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', substr($key, 7), 'id', 'name');
$searchOptions["custom_$id"] = $label;
$key = 'custom_' . CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', substr($key, 7), 'id', 'name');
$label = array_slice(explode(': ', $label, 2), -1);
}
$result[$key] = $label;
}
return $searchOptions;
return $result;
}

/**
Expand Down
151 changes: 60 additions & 91 deletions CRM/Core/BAO/Navigation.php
Expand Up @@ -299,51 +299,6 @@ private static function buildTree($elements, $parentId = NULL) {
return $branch;
}

/**
* Build menu.
*
* @return string
*/
public static function buildNavigation() {
$navigations = self::buildNavigationTree();
$navigationString = '';

// run the Navigation through a hook so users can modify it
CRM_Utils_Hook::navigationMenu($navigations);
self::fixNavigationMenu($navigations);

// Hooks have added menu items in an arbitrary order. We need to order by
// weight again. I would put this function directly after
// CRM_Utils_Hook::navigationMenu but for some reason, fixNavigationMenu is
// moving items added by hooks on the end of the menu. Hence I do it
// afterwards
self::orderByWeight($navigations);

//skip children menu item if user don't have access to parent menu item
$skipMenuItems = array();
foreach ($navigations as $key => $value) {
// Home is a special case
if ($value['attributes']['name'] != 'Home') {
$name = self::getMenuName($value, $skipMenuItems);
if ($name) {
//separator before
if (isset($value['attributes']['separator']) && $value['attributes']['separator'] == 2) {
$navigationString .= '<li class="menu-separator"></li>';
}
$removeCharacters = array('/', '!', '&', '*', ' ', '(', ')', '.');
$navigationString .= '<li class="menumain crm-' . str_replace($removeCharacters, '_', $value['attributes']['label']) . '">' . $name;
}
}
self::recurseNavigation($value, $navigationString, $skipMenuItems);
}

// clean up - Need to remove empty <ul>'s, this happens when user don't have
// permission to access parent
$navigationString = str_replace('<ul></ul></li>', '', $navigationString);

return $navigationString;
}

/**
* buildNavigationTree retreives items in order. We call this function to
* ensure that any items added by the hook are also in the correct order.
Expand Down Expand Up @@ -560,52 +515,6 @@ public static function checkPermission($item) {
return TRUE;
}

/**
* Create navigation for CiviCRM Admin Menu.
*
* @return string
* returns navigation html
*/
public static function createNavigation() {
$navigation = self::buildNavigation();

if ($navigation) {

//add additional navigation items
$logoutURL = CRM_Utils_System::url('civicrm/logout', 'reset=1');

// get home menu from db
$homeParams = array('name' => 'Home');
$homeNav = array();
$homeIcon = '<span class="crm-logo-sm" ></span>';
self::retrieve($homeParams, $homeNav);
if ($homeNav) {
$homeURL = self::makeFullyFormedUrl($homeNav['url']);
$homeLabel = $homeNav['label'];
// CRM-6804 (we need to special-case this as we don’t ts()-tag variables)
if ($homeLabel == 'Home') {
$homeLabel = ts('CiviCRM Home');
}
}
else {
$homeURL = CRM_Utils_System::url('civicrm/dashboard', 'reset=1');
$homeLabel = ts('CiviCRM Home');
}
// Link to hide the menubar
$hideLabel = ts('Hide Menu');

$prepandString = "
<li class='menumain crm-link-home'>$homeIcon
<ul id='civicrm-home'>
<li><a href='$homeURL'>$homeLabel</a></li>
<li><a href='#' class='crm-hidemenu'>$hideLabel</a></li>
<li><a href='$logoutURL' class='crm-logout-link'>" . ts('Log out') . "</a></li>
</ul>";
// <li> tag doesn't need to be closed
}
return $prepandString . $navigation;
}

/**
* Turns relative URLs (like civicrm/foo/bar) into fully-formed
* ones (i.e. example.com/wp-admin?q=civicrm/dashboard).
Expand Down Expand Up @@ -1051,4 +960,64 @@ public static function getCacheKey($cid) {
return $key;
}

/**
* Unset menu items for disabled components and non-permissioned users
*
* @param $menu
*/
public static function filterByPermission(&$menu) {
foreach ($menu as $key => $item) {
if (
(array_key_exists('active', $item['attributes']) && !$item['attributes']['active']) ||
!CRM_Core_BAO_Navigation::checkPermission($item['attributes'])
) {
unset($menu[$key]);
continue;
}
if (!empty($item['child'])) {
self::filterByPermission($menu[$key]['child']);
}
}
}

/**
* @param array $menu
*/
public static function buildHomeMenu(&$menu) {
foreach ($menu as &$item) {
if (CRM_Utils_Array::value('name', $item['attributes']) === 'Home') {
unset($item['attributes']['label'], $item['attributes']['url']);
$item['attributes']['icon'] = 'crm-logo-sm';
$item['attributes']['attr']['accesskey'] = 'm';
$item['child'] = [
[
'attributes' => [
'label' => 'CiviCRM Home',
'name' => 'CiviCRM Home',
'url' => 'civicrm/dashboard?reset=1',
'weight' => 1,
]
],
[
'attributes' => [
'label' => 'Hide Menu',
'name' => 'Hide Menu',
'url' => '#hidemenu',
'weight' => 2,
]
],
[
'attributes' => [
'label' => 'Log out',
'name' => 'Log out',
'url' => 'civicrm/logout?reset=1',
'weight' => 3,
]
],
];
return;
}
}
}

}
68 changes: 49 additions & 19 deletions CRM/Core/Resources.php
Expand Up @@ -591,34 +591,24 @@ public function addCoreResources($region = 'html-header') {
if (is_array($item)) {
$this->addSetting($item);
}
elseif (substr($item, -2) == 'js') {
elseif (strpos($item, '.css')) {
$this->isFullyFormedUrl($item) ? $this->addStyleUrl($item, -100, $region) : $this->addStyleFile('civicrm', $item, -100, $region);
}
elseif ($this->isFullyFormedUrl($item)) {
$this->addScriptUrl($item, $jsWeight++, $region);
}
else {
// Don't bother looking for ts() calls in packages, there aren't any
$translate = (substr($item, 0, 3) == 'js/');
$this->addScriptFile('civicrm', $item, $jsWeight++, $region, $translate);
}
else {
$this->addStyleFile('civicrm', $item, -100, $region);
}
}

$tsLocale = CRM_Core_I18n::getLocale();
// Dynamic localization script
$args = [
'r' => $this->getCacheCode(),
'cid' => CRM_Core_Session::getLoggedInContactID(),
];
$this->addScriptUrl(CRM_Utils_System::url('civicrm/ajax/l10n-js/' . $tsLocale, $args, FALSE, NULL, FALSE), $jsWeight++, $region);

// Add global settings
$settings = array(
'config' => array(
'isFrontend' => $config->userFrameworkFrontend,
),
);
$contactID = CRM_Core_Session::getLoggedInContactID();
if ($contactID) {
$settings['config']['menuCacheCode'] = CRM_Core_BAO_Navigation::getCacheKey($contactID);
}
// Disable profile creation if user lacks permission
if (!CRM_Core_Permission::check('edit all contacts') && !CRM_Core_Permission::check('add contacts')) {
$settings['config']['entityRef']['contactCreate'] = FALSE;
Expand Down Expand Up @@ -694,6 +684,8 @@ public static function outputLocalizationJS() {
'ajaxPopupsEnabled' => self::singleton()->ajaxPopupsEnabled,
'allowAlertAutodismissal' => (bool) Civi::settings()->get('allow_alert_autodismissal'),
'resourceCacheCode' => self::singleton()->getCacheCode(),
'locale' => CRM_Core_I18n::getLocale(),
'cid' => (int) CRM_Core_Session::getLoggedInContactID(),
);
print CRM_Core_Smarty::singleton()->fetchWith('CRM/common/l10n.js.tpl', $vars);
CRM_Utils_System::civiExit();
Expand Down Expand Up @@ -733,6 +725,13 @@ public function coreResourceList($region) {
"js/crm.ajax.js",
"js/wysiwyg/crm.wysiwyg.js",
);

// Dynamic localization script
$items[] = $this->addCacheCode(
CRM_Utils_System::url('civicrm/ajax/l10n-js/' . CRM_Core_I18n::getLocale(),
['cid' => CRM_Core_Session::getLoggedInContactID()], FALSE, NULL, FALSE)
);

// add wysiwyg editor
$editor = Civi::settings()->get('editor_id');
if ($editor == "CKEditor") {
Expand All @@ -748,11 +747,31 @@ public function coreResourceList($region) {
// These scripts are only needed by back-office users
if (CRM_Core_Permission::check('access CiviCRM')) {
$items[] = "packages/jquery/plugins/jquery.tableHeader.js";
$items[] = "packages/jquery/plugins/jquery.menu.min.js";
$items[] = "css/civicrmNavigation.css";
$items[] = "packages/jquery/plugins/jquery.notify.min.js";
}

$contactID = CRM_Core_Session::getLoggedInContactID();

// Menubar
$position = $contactID && CRM_Core_Permission::check('access CiviCRM') ? Civi::settings()->get('menubar_position') : 'none';
if ($position !== 'none' && !@constant('CIVICRM_DISABLE_DEFAULT_MENU') && !CRM_Core_Config::isUpgradeMode()) {
$cms = strtolower(CRM_Core_Config::singleton()->userFramework);
$cms = $cms === 'drupal' ? 'drupal7' : $cms;
$items[] = 'bower_components/smartmenus/dist/jquery.smartmenus.min.js';
$items[] = 'bower_components/smartmenus/dist/addons/keyboard/jquery.smartmenus.keyboard.min.js';
$items[] = 'js/crm.menubar.js';
$items[] = 'bower_components/smartmenus/dist/css/sm-core-css.css';
$items[] = 'css/crm-menubar.css';
$items[] = "css/menubar-$cms.css";
$items[] = [
'menubar' => [
'position' => $position ?: 'over-cms-menu',
'qfKey' => CRM_Core_Key::get('CRM_Contact_Controller_Search', TRUE),
'cacheCode' => CRM_Core_BAO_Navigation::getCacheKey($contactID),
],
];
}

// JS for multilingual installations
if (!empty($config->languageLimit) && count($config->languageLimit) > 1 && CRM_Core_Permission::check('translate CiviCRM')) {
$items[] = "js/crm.multilingual.js";
Expand Down Expand Up @@ -940,4 +959,15 @@ public function addCacheCode($url) {
return $url . $operator . 'r=' . $this->cacheCode;
}

/**
* Checks if the given URL is fully-formed
*
* @param string $url
*
* @return bool
*/
public static function isFullyFormedUrl($url) {
return substr($url, 0, 4) === 'http' || $url[0] === '/';
}

}

0 comments on commit 7062737

Please sign in to comment.