/**
* Build navigation tree.
*
- * @param array $navigationTree
- * Nested array of menus.
- * @param int $parentID
- * Parent id.
- * @param bool $navigationMenu
- * True when called for building top navigation menu.
- *
* @return array
* nested array of menus
*/
- public static function buildNavigationTree(&$navigationTree, $parentID, $navigationMenu = TRUE) {
- $whereClause = " parent_id IS NULL";
-
- if ($parentID) {
- $whereClause = " parent_id = {$parentID}";
- }
-
+ public static function buildNavigationTree() {
$domainID = CRM_Core_Config::domainID();
+ $navigationTree = array();
// get the list of menus
$query = "
SELECT id, label, url, permission, permission_operator, has_separator, parent_id, is_active, name
FROM civicrm_navigation
-WHERE {$whereClause}
-AND domain_id = $domainID
+WHERE domain_id = $domainID
ORDER BY parent_id, weight";
$navigation = CRM_Core_DAO::executeQuery($query);
- $config = CRM_Core_Config::singleton();
while ($navigation->fetch()) {
- $label = $navigation->label;
- if (!$navigationMenu) {
- $label = addcslashes($label, '"');
- }
-
- // for each menu get their children
$navigationTree[$navigation->id] = array(
'attributes' => array(
- 'label' => $label,
+ 'label' => $navigation->label,
'name' => $navigation->name,
'url' => $navigation->url,
'permission' => $navigation->permission,
'active' => $navigation->is_active,
),
);
- self::buildNavigationTree($navigationTree[$navigation->id]['child'], $navigation->id, $navigationMenu);
}
- return $navigationTree;
+ return self::buildTree($navigationTree);
}
/**
- * Build menu.
+ * Convert flat array to nested.
+ *
+ * @param array $elements
+ * @param int|null $parentId
*
- * @param bool $json
- * By default output is html.
- * @param bool $navigationMenu
- * True when called for building top navigation menu.
+ * @return array
+ */
+ private static function buildTree($elements, $parentId = NULL) {
+ $branch = array();
+
+ foreach ($elements as $id => $element) {
+ if ($element['attributes']['parentID'] == $parentId) {
+ $children = self::buildTree($elements, $id);
+ if ($children) {
+ $element['child'] = $children;
+ }
+ $branch[$id] = $element;
+ }
+ }
+
+ return $branch;
+ }
+
+ /**
+ * Build menu.
*
* @return string
- * html or json string
*/
- public static function buildNavigation($json = FALSE, $navigationMenu = TRUE) {
- $navigations = array();
- self::buildNavigationTree($navigations, $parent = NULL, $navigationMenu);
- $navigationString = NULL;
+ 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);
- $i18n = CRM_Core_I18n::singleton();
-
//skip children menu item if user don't have access to parent menu item
$skipMenuItems = array();
foreach ($navigations as $key => $value) {
- if ($json) {
- if ($navigationString) {
- $navigationString .= '},';
- }
- $data = $value['attributes']['label'];
- $class = '';
- if (!$value['attributes']['active']) {
- $class = ', "attr": { "class" : "disabled"} ';
- }
- $l10nName = $i18n->crm_translate($data, array('context' => 'menu'));
- $navigationString .= ' { "attr": { "id" : "node_' . $key . '"}, "data": { "title":"' . $l10nName . '"' . $class . '}';
- }
- else {
- // 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;
+ // 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, $json, $skipMenuItems);
+ self::recurseNavigation($value, $navigationString, $skipMenuItems);
}
- if ($json) {
- $navigationString = '[' . $navigationString . '}]';
- }
- else {
- // 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);
- }
+ // 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;
}
*
* @param array $value
* @param string $navigationString
- * @param bool $json
- * @param bool $skipMenuItems
+ * @param array $skipMenuItems
*
* @return string
*/
- public static function recurseNavigation(&$value, &$navigationString, $json, $skipMenuItems) {
- if ($json) {
- if (!empty($value['child'])) {
- $navigationString .= ', "children": [ ';
- }
- else {
- return $navigationString;
- }
-
- if (!empty($value['child'])) {
- $appendComma = TRUE;
- $count = 1;
- foreach ($value['child'] as $k => $val) {
- if ($count == count($value['child'])) {
- $appendComma = FALSE;
- }
- $data = $val['attributes']['label'];
- $class = '';
- if (!$val['attributes']['active']) {
- $class = ', "attr": { "class" : "disabled"} ';
- }
- $navigationString .= ' { "attr": { "id" : "node_' . $k . '"}, "data": { "title":"' . $data . '"' . $class . '}';
- self::recurseNavigation($val, $navigationString, $json, $skipMenuItems);
- $navigationString .= $appendComma ? ' },' : ' }';
- $count++;
- }
- }
-
- if (!empty($value['child'])) {
- $navigationString .= ' ]';
- }
+ public static function recurseNavigation(&$value, &$navigationString, $skipMenuItems) {
+ if (!empty($value['child'])) {
+ $navigationString .= '<ul>';
}
else {
- if (!empty($value['child'])) {
- $navigationString .= '<ul>';
- }
- else {
- $navigationString .= '</li>';
- //locate separator after
- if (isset($value['attributes']['separator']) && $value['attributes']['separator'] == 1) {
- $navigationString .= '<li class="menu-separator"></li>';
- }
+ $navigationString .= '</li>';
+ //locate separator after
+ if (isset($value['attributes']['separator']) && $value['attributes']['separator'] == 1) {
+ $navigationString .= '<li class="menu-separator"></li>';
}
+ }
- if (!empty($value['child'])) {
- foreach ($value['child'] as $val) {
- $name = self::getMenuName($val, $skipMenuItems);
- if ($name) {
- //locate separator before
- if (isset($val['attributes']['separator']) && $val['attributes']['separator'] == 2) {
- $navigationString .= '<li class="menu-separator"></li>';
- }
- $removeCharacters = array('/', '!', '&', '*', ' ', '(', ')', '.');
- $navigationString .= '<li class="crm-' . str_replace($removeCharacters, '_', $val['attributes']['label']) . '">' . $name;
- self::recurseNavigation($val, $navigationString, $json, $skipMenuItems);
+ if (!empty($value['child'])) {
+ foreach ($value['child'] as $val) {
+ $name = self::getMenuName($val, $skipMenuItems);
+ if ($name) {
+ //locate separator before
+ if (isset($val['attributes']['separator']) && $val['attributes']['separator'] == 2) {
+ $navigationString .= '<li class="menu-separator"></li>';
}
+ $removeCharacters = array('/', '!', '&', '*', ' ', '(', ')', '.');
+ $navigationString .= '<li class="crm-' . str_replace($removeCharacters, '_', $val['attributes']['label']) . '">' . $name;
+ self::recurseNavigation($val, $navigationString, $skipMenuItems);
}
}
- if (!empty($value['child'])) {
- $navigationString .= '</ul></li>';
- if (isset($value['attributes']['separator']) && $value['attributes']['separator'] == 1) {
- $navigationString .= '<li class="menu-separator"></li>';
- }
+ }
+ if (!empty($value['child'])) {
+ $navigationString .= '</ul></li>';
+ if (isset($value['attributes']['separator']) && $value['attributes']['separator'] == 1) {
+ $navigationString .= '<li class="menu-separator"></li>';
}
}
return $navigationString;
CRM_Core_DAO::executeQuery($query);
}
- /**
- * Get the info on navigation item.
- *
- * @param int $navigationID
- * Navigation id.
- *
- * @return array
- * associated array
- */
- public static function getNavigationInfo($navigationID) {
- $query = "SELECT parent_id, weight FROM civicrm_navigation WHERE id = %1";
- $params = array($navigationID, 'Integer');
- $dao = CRM_Core_DAO::executeQuery($query, array(1 => $params));
- $dao->fetch();
- return array(
- 'parent_id' => $dao->parent_id,
- 'weight' => $dao->weight,
- );
- }
-
/**
* Update menu.
*
</span><br/><br/>
</div>
<div class="spacer"></div>
+ <div style="padding-left: 25px;"><div class="crm-logo-sm"></div></div>
<div id="navigation-tree" class="navigation-tree" style="height:auto; border-collapse:separate; background-color:#FFFFFF;"></div>
<div class="spacer"></div>
<div>
<div class="spacer"></div>
</div>
{literal}
- <style type="text/css">
- #navigation-tree li {
- font-weight: normal;
- }
- #navigation-tree > ul > li {
- font-weight: bold;
- }
- </style>
<script type="text/javascript">
CRM.$(function($) {
$("#navigation-tree").jstree({
- plugins: [ "themes", "json_data", "dnd","ui", "crrm","contextmenu" ],
- json_data: {
- ajax:{
- dataType: "json",
- url: {/literal}"{crmURL p='civicrm/ajax/menu' h=0 q='key='}{crmKey name='civicrm/ajax/menu'}"{literal}
+ plugins: ["dnd", "contextmenu"],
+ core: {
+ data: function(tree, callBack) {
+ CRM.api3('Navigation', 'get', {
+ domain_id: {/literal}{$config->domainID()}{literal},
+ options: {limit: 0, sort: 'weight'},
+ return: ['label', 'parent_id'],
+ name: {'!=': 'Home'},
+ sequential: 1
+ }).done(function(data) {
+ var items = [];
+ $.each(data.values, function(key, value) {
+ items.push({
+ id: value.id,
+ text: value.label,
+ icon: false,
+ parent: value.parent_id || '#'
+ });
+ });
+ callBack(items);
+ });
},
- progressive_render: true
- },
- themes: {
- "theme": 'classic',
- "dots": true,
- "icons": false,
- "url": CRM.config.resourceBase + 'packages/jquery/plugins/jstree/themes/classic/style.css'
+ progressive_render: true,
+ check_callback: true
},
- rules: {
- droppable: [ "tree-drop" ],
- multiple: true,
- deletable: "all",
- draggable: "all"
- },
- crrm: {
- move: {
- check_move: function(m) {
- var homeMenuId = {/literal}"{$homeMenuId}"{literal};
- if ( $( m.r[0] ).attr('id').replace("node_","") == homeMenuId ||
- $( m.o[0] ).attr('id').replace("node_","") == homeMenuId ) {
- return false;
- } else {
- return true;
- }
- }
- }
+ dnd: {
+ copy: false
},
contextmenu: {
- items: {
- create: false,
- ccp: {
- label : "{/literal}{ts escape='js'}Edit{/ts}{literal}",
- visible: function (node, obj) { if(node.length != 1) return false;
- return obj.check("renameable", node); },
- action: function (node, obj) {
- var nid = $(node).prop('id');
- var nodeID = nid.substr( 5 );
- var editURL = {/literal}"{crmURL p='civicrm/admin/menu' h=0 q='action=update&reset=1&id='}"{literal} + nodeID;
- CRM.loadForm(editURL).on('crmFormSuccess', function() {
- $("#navigation-tree").jstree('refresh');
- $("#reset-menu").show( );
- });
+ items: function (node, callBack) {
+ var items = {
+ add: {
+ label: "{/literal}{ts escape='js'}Add{/ts}{literal}",
+ icon: 'crm-i fa-plus',
+ action: editForm
+ },
+ edit: {
+ label: "{/literal}{ts escape='js'}Edit{/ts}{literal}",
+ icon: 'crm-i fa-pencil',
+ action: editForm
},
- submenu: false
- }
+ delete: {
+ label: "{/literal}{ts escape='js'}Delete{/ts}{literal}",
+ icon: 'crm-i fa-trash',
+ action: function (menu) {
+ var nodeID = menu.reference.attr('id').replace('_anchor', ''),
+ node = $("#navigation-tree").jstree(true).get_node(nodeID),
+ menuName = node.text;
+ var deleteMsg = {/literal}"{ts escape='js'}Are you sure you want to delete this menu item:{/ts} " + '"'{literal} + menuName + {/literal}'"? {ts escape='js'}This action cannot be undone.{/ts}'{literal};
+ if (node.children.length) {
+ deleteMsg += {/literal}"<br /><br />" + ts('{ts escape='js' 1='<strong>%1</strong>'}%1 sub-menu items will also be deleted.{/ts}'{literal}, {1: node.children.length});
+ }
+ CRM.confirm({message: deleteMsg})
+ .on('crmConfirm:yes', function() {
+ CRM.api3('Navigation', 'delete', {id: nodeID}, true);
+ $("#navigation-tree").jstree(true).delete_node(menu.reference.closest('li'));
+ $("#reset-menu").show();
+ });
+ }
+ }
+ };
+ callBack(items);
}
}
-
- }).bind("rename.jstree", function ( e,node ) {
- var nodeID = node.rslt.obj.attr('id').replace("node_","");
- var newName = node.rslt.new_name;
+ }).on("move_node.jstree", function (e, data) {
+ var nodeID = data.node.id;
+ var refID = data.parent === '#' ? '' : data.parent;
+ var ps = data.position;
var postURL = {/literal}"{crmURL p='civicrm/ajax/menutree' h=0 q='key='}{crmKey name='civicrm/ajax/menutree'}"{literal};
- $.get( postURL + '&type=rename&id=' + nodeID + '&data=' + newName,
- function (data) {
- $("#reset-menu").show( );
- }
- );
-
- }).bind("remove.jstree", function( e,node ) {
- var menuName = node.rslt.obj.find('a').first( ).text( );
- var nodeID = node.rslt.obj.attr('id').replace("node_","");
+ CRM.status({}, $.get( postURL + '&type=move&id=' + nodeID + '&ref_id=' + refID + '&ps='+ps));
+ $("#reset-menu").show();
+ });
- // don't allow deleting of home
- var homeMenuId = {/literal}"{$homeMenuId}"{literal};
- if ( nodeID == homeMenuId ) {
- var cannotDeleteMsg = {/literal}"{ts escape='js'}You cannot delete this menu item:{/ts}" + " "{literal} + menuName;
- CRM.alert( cannotDeleteMsg, {/literal}"{ts escape='js'}Cannot Delete{/ts}"{literal} );
- $("#navigation-tree").jstree('refresh');
- return false;
- }
- var deleteMsg = {/literal}"{ts escape='js'}Are you sure you want to delete this menu item:{/ts}" + " "{literal} + menuName + {/literal}" ? {ts}This action cannot be undone.{/ts}"{literal};
- var isDelete = confirm( deleteMsg );
- if ( isDelete ) {
- var postURL = {/literal}"{crmURL p='civicrm/ajax/menutree' h=0 q='key='}{crmKey name='civicrm/ajax/menutree'}"{literal};
- $.get( postURL + '&type=delete&id=' + nodeID,
- function (data) {
- $("#reset-menu").show( );
- }
- );
+ function editForm(menu) {
+ var nodeID = menu.reference.attr('id').replace('_anchor', ''),
+ action = menu.item.icon === 'crm-i fa-pencil' ? 'update' : 'add',
+ args = {reset: 1, action: action};
+ if (action === 'add') {
+ args.parent_id = nodeID;
} else {
- $("#navigation-tree").jstree('refresh');
+ args.id = nodeID;
}
-
- }).bind("move_node.jstree", function ( e,node ) {
- node.rslt.o.each(function (i) {
- var nodeID = node.rslt.o.attr('id').replace("node_","");
- var refID = node.rslt.np.attr('id').replace("node_","");
- if (isNaN( refID ) ){ refID =''; }
- var ps = node.rslt.cp+i;
- var postURL = {/literal}"{crmURL p='civicrm/ajax/menutree' h=0 q='key='}{crmKey name='civicrm/ajax/menutree'}"{literal};
- $.get( postURL + '&type=move&id=' + nodeID + '&ref_id=' + refID + '&ps='+ps,
- function (data) {
- $("#reset-menu").show( );
- });
+ CRM.loadForm(CRM.url('civicrm/admin/menu', args)).on('crmFormSuccess', function() {
+ $("#navigation-tree").jstree(true).refresh();
+ $("#reset-menu").show();
});
- });
+ }
+
$('#new-menu-item a.button')
.on('click', CRM.popup)
.on('crmPopupFormSuccess', function() {
- $("#navigation-tree").jstree('refresh');
+ $("#navigation-tree").jstree(true).refresh();
$("#reset-menu").show();
});
CRM.api3('Navigation', 'reset', {'for': 'report'}, true)
.done(function() {
$('#crm-container').unblock();
- $("#navigation-tree").jstree('refresh');
+ $("#navigation-tree").jstree(true).refresh();
$("#reset-menu").show();
})
});