class CRM_Admin_Page_AJAX {
/**
- * Function to build menu tree
+ * CRM-12337 Output navigation menu as executable javascript
+ * @see smarty_function_crmNavigationMenu
+ */
+ static function getNavigationMenu() {
+ $session = CRM_Core_Session::singleton();
+ $contactID = $session->get('userID');
+ if ($contactID) {
+ // Set headers to encourage browsers to cache for a long time
+ // If we want to refresh the menu we will send a different url
+ // @see smarty_function_crmNavigationMenu()
+ $year = 60*60*24*364;
+ header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + $year));
+ header('Content-Type: application/javascript');
+ header("Cache-Control: max-age=$year, public");
+
+ // Render template as a javascript file
+ $smarty = CRM_Core_Smarty::singleton();
+ $navigation = CRM_Core_BAO_Navigation::createNavigation($contactID);
+ $smarty->assign('navigation', $navigation);
+ print $smarty->fetch('CRM/common/Navigation.tpl');
+ }
+ exit();
+ }
+
+ /**
+ * Return menu tree as json data for editing
*/
static function getNavigationList() {
echo CRM_Core_BAO_Navigation::buildNavigation(TRUE, FALSE);
* Function to process drag/move action for menu tree
*/
static function menuTree() {
- echo CRM_Core_BAO_Navigation::processNavigation($_GET);
- CRM_Utils_System::civiExit();
+ CRM_Core_BAO_Navigation::processNavigation($_GET);
}
/**
*/
class CRM_Core_BAO_Navigation extends CRM_Core_DAO_Navigation {
+ // Number of characters in the menu js cache key
+ const CACHE_KEY_STRLEN = 8;
+
/**
* class constructor
*/
static function createNavigation($contactID) {
$config = CRM_Core_Config::singleton();
- // if on frontend, do not create navigation menu items, CRM-5349
- if ($config->userFrameworkFrontend) {
- return "<!-- $config->lcMessages -->";
- }
+ $navigation = self::buildNavigation();
- $navParams = array('contact_id' => $contactID);
-
- $navigation = CRM_Core_BAO_Setting::getItem(
- CRM_Core_BAO_Setting::PERSONAL_PREFERENCES_NAME,
- 'navigation',
- NULL,
- NULL,
- $contactID
- );
-
- // FIXME: hack for CRM-5027: we need to prepend the navigation string with
- // (HTML-commented-out) locale info so that we rebuild menu on locale changes
- if (
- !$navigation ||
- substr($navigation, 0, 14) != "<!-- $config->lcMessages -->"
- ) {
- //retrieve navigation if it's not cached.
- $navigation = self::buildNavigation();
+ if ($navigation) {
//add additional navigation items
$logoutURL = CRM_Utils_System::url('civicrm/logout', 'reset=1');
$prepandString = "<li class=\"menumain crm-link-home\"><a href=\"{$homeURL}\" title=\"" . $homeLabel . "\">" . $homeLabel . "</a></li>";
}
- // prepend the navigation with locale info for CRM-5027
- $navigation = "<!-- $config->lcMessages -->" . $prepandString . $navigation . $appendSring;
+ $navigation = $prepandString . $navigation . $appendSring;
+ }
+ return $navigation;
+ }
+ /**
+ * Reset navigation for all contacts or a specified contact
+ *
+ * @param integer $contactID - reset only entries belonging to that contact ID
+ * @return string
+ */
+ static function resetNavigation($contactID = NULL) {
+ $newKey = CRM_Utils_String::createRandom(self::CACHE_KEY_STRLEN, CRM_Utils_String::ALPHANUMERIC);
+ if (!$contactID) {
+ $query = "UPDATE civicrm_setting SET value = '$newKey' WHERE name='navigation' AND contact_id IS NOT NULL";
+ CRM_Core_DAO::executeQuery($query);
+ CRM_Core_BAO_Cache::deleteGroup('navigation');
+ }
+ else {
// before inserting check if contact id exists in db
- // this is to handle wierd case when contact id is in session but not in db
+ // this is to handle weird case when contact id is in session but not in db
$contact = new CRM_Contact_DAO_Contact();
$contact->id = $contactID;
if ($contact->find(TRUE)) {
CRM_Core_BAO_Setting::setItem(
- $navigation,
+ $newKey,
CRM_Core_BAO_Setting::PERSONAL_PREFERENCES_NAME,
'navigation',
NULL,
);
}
}
- return $navigation;
- }
-
- /**
- * Reset navigation for all contacts
- *
- * @param integer $contactID - reset only entries belonging to that contact ID
- */
- static function resetNavigation($contactID = NULL) {
- $params = array();
- $query = "UPDATE civicrm_setting SET value = NULL WHERE name='navigation'";
- if ($contactID) {
- $query .= " AND contact_id = %1";
- $params[1] = array($contactID, 'Integer');
- }
- else {
- $query .= " AND contact_id IS NOT NULL";
- }
-
- CRM_Core_DAO::executeQuery($query, $params);
- CRM_Core_BAO_Cache::deleteGroup('navigation');
-
// also reset the dashlet cache in case permissions have changed etc
+ // FIXME: decouple this
CRM_Core_BAO_Dashboard::resetDashletCache($contactID);
+
+ return $newKey;
}
/**
$dao->save();
}
}
+
+ static function getCacheKey($cid) {
+ $key = CRM_Core_BAO_Setting::getItem(
+ CRM_Core_BAO_Setting::PERSONAL_PREFERENCES_NAME,
+ 'navigation',
+ NULL,
+ '',
+ $cid
+ );
+ if (strlen($key) !== self::CACHE_KEY_STRLEN) {
+ $key = self::resetNavigation($cid);
+ }
+ return $key;
+ }
}
*/
/**
- * Generate the nav menu
+ * Output navigation script tag
*
* @param array $params
* - is_default: bool, true if this is normal/default instance of the menu (which may be subject to CIVICRM_DISABLE_DEFAULT_MENU)
* @return string HTML
*/
function smarty_function_crmNavigationMenu($params, &$smarty) {
+ $config = CRM_Core_Config::singleton();
//check if logged in user has access CiviCRM permission and build menu
$buildNavigation = !CRM_Core_Config::isUpgradeMode() && CRM_Core_Permission::check('access CiviCRM');
if (defined('CIVICRM_DISABLE_DEFAULT_MENU') && CRM_Utils_Array::value('is_default', $params, FALSE)) {
$buildNavigation = FALSE;
}
+ if ($config->userFrameworkFrontend) {
+ $buildNavigation = FALSE;
+ }
if ($buildNavigation) {
$session = CRM_Core_Session::singleton();
$contactID = $session->get('userID');
if ($contactID) {
- $navigation = CRM_Core_BAO_Navigation::createNavigation($contactID);
- $smarty->assign('navigation', $navigation);
- return $smarty->fetch('CRM/common/Navigation.tpl');
+ // These params force the browser to refresh the js file when switching user, domain, or language
+ // We don't put them as a query string because some browsers will refuse to cache a page with a ? in the url
+ // We end the string with .js to trick apache mods into sending pro-caching headers
+ // @see CRM_Admin_Page_AJAX::getNavigationMenu
+ $lang = $config->lcMessages;
+ $domain = CRM_Core_Config::domainID();
+ $key = CRM_Core_BAO_Navigation::getCacheKey($contactID);
+ $src = CRM_Utils_System::url("civicrm/ajax/menujs/$contactID/$lang/$domain/$key.js");
+ return '<script type="text/javascript" src="' . $src . '"></script>';
}
}
return '';
<title>Option Values</title>
<page_callback>CRM_Admin_Page_OptionValue</page_callback>
</item>
+ <item>
+ <path>civicrm/ajax/menujs</path>
+ <page_callback>CRM_Admin_Page_AJAX::getNavigationMenu</page_callback>
+ <access_arguments>access CiviCRM</access_arguments>
+ </item>
<item>
<path>civicrm/ajax/menu</path>
<page_callback>CRM_Admin_Page_AJAX::getNavigationList</page_callback>
{/if}
{$navigation}
</ul>
-{/strip}{/capture}
-{literal}
-<script type="text/javascript">
+{/strip}{/capture}{literal}
(function($) {
var menuMarkup = {/literal}{$menuMarkup|@json_encode}{literal};
$(function() {
});
{/literal}{/if}{literal}
$('#civicrm-menu').menu({arrowSrc: CRM.config.resourceBase + 'packages/jquery/css/images/arrow.png'});
- })(cj);
-</script>
-{/literal}
+ })(cj);{/literal}