summaryrefslogtreecommitdiffstats
path: root/ecomp-portal-FE/client/app/views/functionalMenu
diff options
context:
space:
mode:
Diffstat (limited to 'ecomp-portal-FE/client/app/views/functionalMenu')
-rw-r--r--ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.controller.js384
-rw-r--r--ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.delete.modal.html35
-rw-r--r--ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html106
-rw-r--r--ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/modal-details.modal.less103
-rw-r--r--ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.controller.js331
-rw-r--r--ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.less70
-rw-r--r--ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.tpl.html48
-rw-r--r--ecomp-portal-FE/client/app/views/functionalMenu/jqTreeContextMenu.js192
8 files changed, 1269 insertions, 0 deletions
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.controller.js b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.controller.js
new file mode 100644
index 00000000..0d27d868
--- /dev/null
+++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.controller.js
@@ -0,0 +1,384 @@
+/*-
+ * ================================================================================
+ * eCOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ================================================================================
+ */
+'use strict';
+(function () {
+ class MenuDetailsModalCtrl {
+ constructor($scope, $log, functionalMenuService, errorMessageByCode, ECOMP_URL_REGEX,$rootScope,confirmBoxService) {
+ let newMenuModel = {
+ name: null,
+ menuId: null,
+ parentMenuId: null,
+ url: null
+ };
+
+ let getAvailableRoles = (appid) => {
+ this.isSaving = true;
+ if (appid != null) {
+ $log.debug("MenuDetailsModalCtrl::getAvailableRoles: About to call getManagedRolesMenu");
+ functionalMenuService.getManagedRolesMenu(appid).then(rolesObj => {
+ $log.debug("MenuDetailsModalCtrl::getAvailableRoles: Roles returned = " + JSON.stringify(rolesObj))
+ this.availableRoles = rolesObj;
+ this.preSelectedRoles = {roles:[]};
+
+ if(($scope.ngDialogData.source=='edit') && this.isMidLevelMenuItem()){
+ this.preSelectedRoles = {roles:[]};
+ }else if(!angular.isUndefined(this.menuItem.menuDetails) &&
+ $scope.ngDialogData.source=='edit' && this.isLeafMenuItem() &&
+ this.menuItem.menuDetails.appid!=appid) {
+ this.preSelectedRoles = {roles:[]};
+ }else{
+ if((!angular.isUndefined(this.menuItem.menuDetails)) &&
+ (!angular.isUndefined(this.menuItem.menuDetails.roles))){
+ $log.debug('menuDetails.roles: ' + this.menuItem.menuDetails.roles);
+ for(var i=0; i<this.menuItem.menuDetails.roles.length; i++){
+ var role = {"roleId":this.menuItem.menuDetails.roles[i]};
+ $log.debug('MenuDetailsModalCtrl::getAvailableRoles: adding role to preselected: ' + i + ': ' + JSON.stringify(role));
+ this.preSelectedRoles.roles.push(role);
+ }
+ }
+ }
+ $rootScope.$broadcast('availableRolesReady');
+ this.isSaving = false;
+ }).catch(err => {
+ $log.error("MenuDetailsModalCtrl::getAvailableRoles: error: " + err);
+ });
+ } else {
+ $log.debug("MenuDetailsModalCtrl::getAvailableRoles: appid was null");
+ }
+ };
+
+ let getAvailableApps = () => {
+ functionalMenuService.getAvailableApplications().then(apps => {
+ $log.debug("MenuDetailsModalCtrl::getAvailableApps: Apps returned = " + JSON.stringify(apps))
+ this.availableApps = apps;
+ if (angular.isDefined(this.selectedApp) && angular.isDefined(this.selectedApp.index)) {
+ for (var i = 0; i < apps.length; i++) {
+ if (apps[i].index === this.selectedApp.index) {
+ $log.debug("MenuDetailsModalCtrl::getAvailableApps: found app with index: " + this.selectedApp.index);
+ $log.debug("MenuDetailsModalCtrl::getAvailableApps: setting isDisabled to: " + !apps[i].enabled);
+ this.selectedApp.isDisabled = !apps[i].enabled;
+ break;
+ }
+ }
+ $log.debug("didn't find index: " + this.selectedApp.index);
+ }
+ })['catch'](function (err) {
+ $log.error("MenuDetailsModalCtrl::getAvailableApps: getAvailableApps error: " + err);
+ }).finally(()=>{
+ this.isSaving = false;
+ });
+ };
+
+ let init = () => {
+ $log.info('MenuDetailsModalCtrl::init');
+ this.saveOrContinueBtnText = "Save";
+ this.isSaving = false;
+ this.displayRoles = $scope.ngDialogData.source=='view' ? true : false;
+ this.formEditable = $scope.ngDialogData.source=='view' ? false : true;
+ this.selectedRole = [];
+ this.availableRoles = [];
+ this.menuItem = _.clone($scope.ngDialogData.menuItem);
+ $log.info('MenuDetailsModalCtrl::getAvailableApps: Within init, about to check menuDetails for defined');
+ if(!angular.isUndefined(this.menuItem.menuDetails) &&
+ ($scope.ngDialogData.source=='view' ||
+ ($scope.ngDialogData.source=='edit') && this.isLeafMenuItem() )){
+
+ $log.debug("MenuDetailsModalCtrl::init: menuItem: ");
+ $log.debug('MenuDetailsModalCtrl::init: ',this.menuItem);
+ this.menuItem.menu.url = this.menuItem.menuDetails.url;
+ this.selectedApp={};
+ this.selectedApp.index = this.menuItem.menuDetails.appid;
+ getAvailableRoles(this.selectedApp.index);
+
+ }
+
+ if($scope.ngDialogData.source=='view' || $scope.ngDialogData.source=='edit'){
+ this.menutitle = this.menuItem.menu.name;
+ this.menuLocation = this.isParentMenuItem() ? this.menuItem.menu.name : this.menuItem.menu.parent.name;
+ }else{
+ this.menutitle = '';
+ this.menuLocation = this.menuItem.menu.name;
+ }
+ getAvailableApps();
+ $log.debug("MenuDetailsModalCtrl::init: Menu details: " + JSON.stringify(this.menuItem.menuDetails));
+ };
+
+
+ this.ECOMP_URL_REGEX = ECOMP_URL_REGEX;
+
+ this.conflictMessages = {};
+ this.scrollApi = {};
+ let handleConflictErrors = err => {
+ if(!err.data){
+ return;
+ }
+ if(!err.data.length){
+ err.data = [err.data]
+ }
+ $log.debug('MenuDetailsModalCtrl::handleConflictErrors: err.data = ' + JSON.stringify(err.data));
+ _.forEach(err.data, item => {
+ _.forEach(item.fields, field => {
+ this.conflictMessages[field.name] = errorMessageByCode[item.errorCode];
+ $log.debug('MenuDetailsModalCtrl::handleConflictErrors: fieldName = ' + field.name);
+ $scope.functionalMenuForm[field.name].$setValidity('conflict', false);
+ watchOnce[field.name]();
+ });
+ });
+ this.scrollApi.scrollTop();
+ };
+
+ let resetConflict = fieldName => {
+ delete this.conflictMessages[fieldName];
+ $log.debug('MenuDetailsModalCtrl::resetConflict: $setValidity(true) = ' + fieldName);
+ if($scope.functionalMenuForm[fieldName]){
+ $scope.functionalMenuForm[fieldName].$setValidity('conflict', true);
+ }
+ };
+
+ let watchOnce = {
+ text: () => {
+ let unregisterName = $scope.$watch('functionalMenuDetails.menutitle', (newVal, oldVal) => {
+ if(newVal.toLowerCase() !== oldVal.toLowerCase()){
+ resetConflict('text');
+ unregisterName();
+ }
+ });
+ },
+ url: () => {
+ let unregisterUrl = $scope.$watch('functionalMenuDetails.menuItem.menu.url', (newVal, oldVal) => {
+ if(newVal.toLowerCase() !== oldVal.toLowerCase()){
+ resetConflict('url');
+ unregisterUrl();
+ }
+ });
+ }
+ };
+
+ //***************************
+
+ this.isLeafMenuItem = () => {
+ return this.menuItem.menu.children.length>0 ? false : true;
+ };
+
+ this.isMidLevelMenuItem = () => {
+ return this.menuItem.menu.parentMenuId!=null && this.menuItem.menu.children.length>0 ? true : false;
+ };
+
+ this.isParentMenuItem = () => {
+ return this.menuItem.menu.parentMenuId!=null ? false : true;
+ };
+
+ this.updateSelectedApp = (appItem) => {
+ if (!appItem) {
+ return;
+ }
+ $log.debug('MenuDetailsModalCtrl::updateSelectedApp: drop down app item = ' + JSON.stringify(appItem.index));
+ $log.debug("MenuDetailsModalCtrl::updateSelectedApp: appItem in updateSelectedApp: ");
+ $log.debug('MenuDetailsModalCtrl::updateSelectedApp: ',appItem);
+ this.selectedApp.isDisabled = ! appItem.enabled;
+ $log.debug("MenuDetailsModalCtrl::updateSelectedApp: isDisabled: "+this.selectedApp.isDisabled);
+ getAvailableRoles(appItem.index);
+ };
+
+ this.continue = () => {
+ this.displayRoles = true;
+ this.formEditable = false;
+ };
+
+ this.saveChanges = () => {
+
+ if(!!this.menuItem.menu.url && (angular.isUndefined(this.selectedApp) || !this.selectedApp.index>0)) {
+ confirmBoxService.showInformation('Please select the appropriate app, or remove the url').then(isConfirmed => {});
+ return;
+ }else if(!this.menuItem.menu.url && !angular.isUndefined(this.selectedApp) && this.selectedApp.index>0){
+ confirmBoxService.showInformation('Please enter url, or select "No Application"').then(isConfirmed => {});
+ return;
+ }else if(!this.menutitle){
+ confirmBoxService.showInformation('Please enter the Menu title').then(isConfirmed => {});
+ return;
+ }
+
+ this.isSaving = true;
+ var activeMenuItem = {};
+
+ if ($scope.ngDialogData.source == 'edit') {
+ $log.debug('MenuDetailsModalCtrl::saveChanges: Will be saving an edit menu item');
+ activeMenuItem = {
+ menuId:this.menuItem.menu.menuId,
+ column:this.menuItem.menu.column,
+ text:this.menutitle,
+ parentMenuId:this.menuItem.menu.parentMenuId,
+ url:this.menuItem.menu.url,
+ appid: angular.isUndefined(this.selectedApp) ? null:this.selectedApp.index,
+ roles:this.selectedRole
+ };
+ if (!activeMenuItem.appid && !activeMenuItem.url) {
+ activeMenuItem.roles = null;
+ }
+ functionalMenuService.saveEditedMenuItem(activeMenuItem)
+ .then(() => {
+ $log.debug('MenuDetailsModalCtrl::saveChanges: Menu Item saved');
+ $scope.closeThisDialog(true);
+ }).catch(err => {
+ if(err.status === 409){
+ handleConflictErrors(err);
+ }
+ $log.error('MenuDetailsModalCtrl::saveChanges: error - ',err);
+ }).finally(()=>{
+ this.isSaving = false;
+ });
+
+ $log.debug("MenuDetailsModalCtrl::saveChanges: Edit Menu output will be: " + JSON.stringify(activeMenuItem));
+ } else {
+ $log.debug('MenuDetailsModalCtrl::saveChanges: Will be saving a New menu item');
+ var newMenuItem = {
+ menuId:null,
+ column:this.menuItem.menu.column,
+ text:this.menutitle,
+ parentMenuId:this.menuItem.menu.menuId,
+ url:this.menuItem.menu.url,
+ appid: angular.isUndefined(this.selectedApp) ? null:this.selectedApp.index,
+ roles:this.selectedRole
+ };
+
+ $log.debug("MenuDetailsModalCtrl::saveChanges: New Menu output will be: " + JSON.stringify(newMenuItem));
+ functionalMenuService.saveMenuItem(newMenuItem)
+ .then(() => {
+ $log.debug('MenuDetailsModalCtrl::saveChanges: Menu Item saved');
+ $scope.closeThisDialog(true);
+ }).catch(err => {
+ if(err.status === 409){//Conflict
+ handleConflictErrors(err);
+ }
+ $log.error('MenuDetailsModalCtrl::saveChanges error: ', err);
+ }).finally(()=>{
+ this.isSaving = false;
+ });
+
+ }
+ };
+
+ init();
+
+ $scope.$on('$stateChangeStart', e => {
+ e.preventDefault();
+ });
+ }
+ }
+ MenuDetailsModalCtrl.$inject = ['$scope', '$log', 'functionalMenuService', 'errorMessageByCode', 'ECOMP_URL_REGEX','$rootScope','confirmBoxService'];
+ angular.module('ecompApp').controller('MenuDetailsModalCtrl', MenuDetailsModalCtrl);
+
+ angular.module('ecompApp').directive('dropdownMultiselect', ['functionalMenuService',function(){
+ return {
+ restrict: 'E',
+ scope: {
+ model: '=',
+ options: '=',
+ populated_roles: '=preSelected',
+ dropdownTitle: '@',
+ source: '='
+ },
+ template: "<div class='btn-group' data-ng-class='{open: open}'>" +
+ "<button class='btn btn-medium'>{{dropdownTitle}}</button>" +
+ "<button class='btn dropdown-toggle' data-ng-click='open=!open;openDropDown()'><span class='caret'></span></button>" +
+ "<ul class='dropdown-menu dropdown-menu-medium' aria-labelledby='dropdownMenu'>" +
+ "<li data-ng-repeat='option in options'> <input ng-disabled='setDisable(source)' type='checkbox' data-ng-change='setSelectedItem(option.roleId)' ng-model='selectedItems[option.roleId]'>{{option.rolename}}</li>" +
+ "</ul>" +
+ "</div>",
+ controller: function ($scope) {
+ $scope.selectedItems = {};
+ $scope.checkAll = false;
+ $scope.$on('availableRolesReady', function() {
+ init();
+ });
+
+ function init() {
+ console.log('dropdownMultiselect init');
+ $scope.dropdownTitle = $scope.source =='view' ? 'View Roles' : 'Select Roles';
+ console.log('$scope.populated_roles = ' + $scope.populated_roles);
+ }
+
+ $scope.$watch('populated_roles', function(){
+ if ($scope.populated_roles && $scope.populated_roles.length>0) {
+ for (var i = 0; i < $scope.populated_roles.length; i++) {
+ $scope.model.push($scope.populated_roles[i].roleId);
+ $scope.selectedItems[$scope.populated_roles[i].roleId] = true;
+ }
+ if ($scope.populated_roles.length == $scope.options.length) {
+ $scope.checkAll = true;
+ }
+ }else{
+ deselectAll();
+ }
+ });
+
+ $scope.openDropDown = function () {
+
+ };
+
+ $scope.checkAllClicked = function () {
+ if ($scope.checkAll) {
+ selectAll();
+ } else {
+ deselectAll();
+ }
+ };
+
+ function selectAll() {
+ $scope.model = [];
+ $scope.selectedItems = {};
+ angular.forEach($scope.options, function (option) {
+ $scope.model.push(option.roleId);
+ });
+ angular.forEach($scope.model, function (id) {
+ $scope.selectedItems[id] = true;
+ });
+ console.log($scope.model);
+ };
+
+ function deselectAll() {
+ $scope.model = [];
+ $scope.selectedItems = {};
+ console.log($scope.model);
+ };
+
+ $scope.setSelectedItem = function (id) {
+ var filteredArray = [];
+ if ($scope.selectedItems[id] == true) {
+ $scope.model.push(id);
+ } else {
+ filteredArray = $scope.model.filter(function (value) {
+ return value != id;
+ });
+ $scope.model = filteredArray;
+ $scope.checkAll = false;
+ }
+ console.log(filteredArray);
+ return false;
+ };
+
+ $scope.setDisable = function(source){
+ return source =='view' ? true : false;
+ }
+ }
+ }
+ }]);
+
+})();
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.delete.modal.html b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.delete.modal.html
new file mode 100644
index 00000000..7157886b
--- /dev/null
+++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.delete.modal.html
@@ -0,0 +1,35 @@
+<!--
+ ================================================================================
+ eCOMP Portal
+ ================================================================================
+ Copyright (C) 2017 AT&T Intellectual Property
+ ================================================================================
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ================================================================================
+ -->
+<div class="functionalMenu-details-modal">
+ <div class="title">Delete Menu Item</div>
+ <div class="functionalMenu-properties-main" scroll-top="functionalMenuDetails.scrollApi">
+ <form name="functionalMenuForm" novalidate>
+ <div class="confirmation-message-wrap">
+ <div class="confirmation-message" ng-bind="confirmBox.message"></div>
+ </div>
+ </form>
+ </div>
+ <div class="dialog-control">
+ <span class="ecomp-save-spinner" ng-show="functionalMenuDetails.isSaving"></span>
+ <div id='menu-details-next-button' class="next-button"
+ ng-class="{disabled: functionalMenuForm.$invalid}" ng-click="functionalMenuDetails.saveChanges()">Delete</div>
+ <div class="cancel-button" ng-click="closeThisDialog()">Cancel</div>
+ </div>
+</div>
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html
new file mode 100644
index 00000000..58588ce5
--- /dev/null
+++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html
@@ -0,0 +1,106 @@
+<!--
+ ================================================================================
+ eCOMP Portal
+ ================================================================================
+ Copyright (C) 2017 AT&T Intellectual Property
+ ================================================================================
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ================================================================================
+ -->
+<div class="functionalMenu-details-modal">
+ <div class="title">{{ngDialogData.title}}</div>
+ <div class="functionalMenu-properties-main" scroll-top="functionalMenuDetails.scrollApi">
+ <form name="functionalMenuForm">
+ <div class="item">
+ <div class="item-label">Parent</div>
+ <input id="input-parent" readonly="readonly" class="input-field"
+ value="{{functionalMenuDetails.menuLocation}}" type="text" name="menuItem" required/>
+ </div>
+ <div class="item">
+ <div class="item-label">Title</div>
+ <input id="input-title" ng-readonly="!functionalMenuDetails.formEditable ? 'checked':'' "
+ placeholder="Enter text" class="input-field" ng-model="functionalMenuDetails.menutitle" type="text" name="text"/>
+ <div id="div-error-conflict" class="error-container" ng-show="functionalMenuDetails.conflictMessages.text">
+ <small id="msg-error-conflict" id="functionalMenuDetails-input-title-conflict"
+ class="err-message" ng-bind="functionalMenuDetails.conflictMessages.text"></small>
+ </div>
+ </div>
+ <div class="item">
+ <div class="left-item">
+ <div class="item-label">URL</div>
+ <input id="input-url" ng-readonly="!functionalMenuDetails.formEditable ? 'checked':'' "
+ placeholder="http://" class="input-field" ng-model="functionalMenuDetails.menuItem.menu.url" type="url" name="url"/>
+ <span id="error-url-conflict" class="err-message" ng-show="functionalMenuForm.url.$error.url"> Not valid URL!</span>
+ </div>
+ <div class="right-item">
+ <div class="item-label">App</div>
+ <div class="custom-select-wrap" ng-readonly="checked">
+ <select id="select-app" class="select-field"
+ ng-model="functionalMenuDetails.selectedApp"
+ ng-change="functionalMenuDetails.updateSelectedApp(functionalMenuDetails.selectedApp);"
+ ng-options="app.title for app in functionalMenuDetails.availableApps track by app.index"
+ ng-disabled="!functionalMenuDetails.availableApps || !functionalMenuDetails.availableApps.length
+ || !functionalMenuDetails.formEditable"
+ name="app"
+ required>
+ <option value="" >No Application</option>
+ </select>
+ </div>
+ </div>
+ </div>
+ <div class="item" ng-show="functionalMenuDetails.displayRoles==true">
+ <div class="item-label">Roles</div>
+ <dropdown-multiselect id="dropdown-roles" dropdown-title="Select Roles"
+ pre-selected="functionalMenuDetails.preSelectedRoles.roles"
+ model="functionalMenuDetails.selectedRole"
+ options="functionalMenuDetails.availableRoles" source="ngDialogData.source">
+ </dropdown-multiselect>
+ </div>
+ <div ng-show="functionalMenuDetails.selectedApp && functionalMenuDetails.selectedApp.isDisabled" class="err-message">Application is disabled</div>
+ </form>
+ </div>
+ <div class="dialog-control">
+ <div ng-if="ngDialogData.source!='view'">
+ <span class="ecomp-save-spinner" ng-show="functionalMenuDetails.isSaving"></span>
+ <span ng-if="ngDialogData.source=='edit' && functionalMenuDetails.isLeafMenuItem()">
+ <button class="save-button" id="add-menu-button-save"
+ ng-show="!functionalMenuDetails.menuItem.menu.url ||
+ !(functionalMenuDetails.selectedApp.index>0) ||
+ functionalMenuDetails.displayRoles"
+ ng-disabled="!functionalMenuForm.text.$valid"
+ ng-click="functionalMenuDetails.saveChanges()">Save</button>
+ <button class="save-button" id="add-menu-button-continue"
+ ng-show="!!functionalMenuDetails.menuItem.menu.url &&
+ functionalMenuDetails.selectedApp.index>0 &&
+ functionalMenuDetails.menutitle &&
+ !functionalMenuDetails.displayRoles"
+ ng-disabled="!functionalMenuForm.url.$valid" ng-click="functionalMenuDetails.continue()">Continue</button>
+ </span>
+ <span ng-if="ngDialogData.source=='add' || (ngDialogData.source=='edit' && !functionalMenuDetails.isLeafMenuItem())">
+ <button id="button-save-add"
+ class="save-button" ng-show="!functionalMenuDetails.menuItem.menu.url || !(functionalMenuDetails.selectedApp.index>0)
+ || functionalMenuDetails.selectedRole.length>0 || !functionalMenuDetails.menutitle" ng-disabled="!functionalMenuForm.text.$valid || !functionalMenuDetails.menutitle"
+ ng-click="functionalMenuDetails.saveChanges()">Save</button>
+ <button id="button-save-continue" class="save-button"
+ ng-show="!!functionalMenuDetails.menuItem.menu.url && functionalMenuDetails.selectedApp.index>0
+ && functionalMenuDetails.menutitle
+ && !functionalMenuDetails.selectedRole.length>0" ng-disabled="!functionalMenuForm.url.$valid"
+ ng-click="functionalMenuDetails.continue()">Continue</button>
+ </span>
+ <button id="button-cancel-close-dialog" class="cancel-button" ng-click="closeThisDialog()">Cancel</button>
+ </div>
+ <div ng-if="ngDialogData.source=='view'">
+ <div id="div-close-dialog" class="cancel-button" ng-click="closeThisDialog()">Close</div>
+ </div>
+ </div>
+</div>
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/modal-details.modal.less b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/modal-details.modal.less
new file mode 100644
index 00000000..c322f453
--- /dev/null
+++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu-dialog/modal-details.modal.less
@@ -0,0 +1,103 @@
+/*-
+ * ================================================================================
+ * eCOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ================================================================================
+ */
+ .functionalMenu-details-modal {
+ height: 430px;
+
+ .title {
+ .n18r;
+ border-bottom: @a 3px solid;
+
+ }
+
+ .btn-medium{
+ width:216px;
+ }
+ .dropdown-menu-medium{
+ width:236px;
+ max-height: 200px;
+ overflow-y: auto;
+ }
+
+ .functionalMenu-properties-main {
+ padding: 16px;
+ height: 306px;
+ overflow-y: visible;
+
+ .item{
+ position: relative;
+ margin-bottom: 18px;
+
+ .input-field{
+ .custom-input-field;
+ width: 100%;
+ &.url{
+ width: 78%;
+ display: inline-block;
+ }
+ }
+
+ .select-field {
+ .custom-select-field;
+ }
+
+ .item-label{
+ .o14r;
+ }
+
+ .right-item{
+ position: relative;
+ display: inline-block;
+ width: 48%;
+ float: right;
+ }
+ .left-item{
+ display: inline-block;
+ width: 48%;
+ }
+
+ .url-validation-button{
+ .btn-blue;
+ width: 20%;
+ display: inline-block;
+ float: right;
+ }
+
+ .error-container{
+ position: absolute;
+ width: 220px;
+ display: block;
+ height: 12px;
+ line-height: 12px;
+
+ .err-message{
+ color: red;
+ font-size: 9px;
+ }
+ .valid-message{
+ color: green;
+ font-size: 9px;
+ }
+ }
+
+ }
+
+ }
+
+}
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.controller.js b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.controller.js
new file mode 100644
index 00000000..d17c4ab8
--- /dev/null
+++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.controller.js
@@ -0,0 +1,331 @@
+/*-
+ * ================================================================================
+ * eCOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ================================================================================
+ */
+'use strict';
+(function () {
+ class FunctionalMenuCtrl {
+ constructor($log, functionalMenuService, $scope,ngDialog, confirmBoxService) {
+ $log.info('FunctionalMenuCtrl init');
+
+ $scope.invokeDialog = () => {
+ alert("click dialog");
+ };
+
+ this.regenerateFunctionalMenuAncestors = () => {
+ functionalMenuService.regenerateFunctionalMenuAncestors().then(res => {
+ $log.debug("FunctionalMenuCtrl:regenerateFunctionalMenuAncestors::returned from regenerateFunctionalMenuAncestors API call");
+ confirmBoxService.showInformation('You have successfully regenerated the menu.').then(isConfirmed => {
+ });
+ })['catch'](function (err) {
+ $log.error("FunctionalMenuCtrl:regenerateFunctionalMenuAncestors:: error: " + err);
+ confirmBoxService.showInformation('There was an error while regenerating the menu.').then(isConfirmed => {
+ });
+ });
+ };
+
+ let getFunctionalMenu = () => {
+ this.isLoadingTable = true;
+ functionalMenuService.getManagedFunctionalMenu().then(res => {
+
+ let actualData=[];
+
+ for(let i = 0; i < res.length; i++){
+ res[i].children=[];
+ res[i].label=res[i].text;
+ res[i].id=res[i].text;
+
+ }
+
+ for(let i = 0; i < res.length; i++){
+
+ let parentId=res[i].menuId;
+ for(let j = 0; j < res.length; j++){
+ let childId=res[j].parentMenuId;
+ if(parentId==childId){
+ res[i].children.push(res[j]);
+
+ }
+ }
+ }
+
+ res.sort(function(a, b) {
+ return a.column-b.column;
+ })
+
+ for(let i = 0; i < res.length; i++){
+ res[i].children.sort(function(a, b){
+ return a.column-b.column;
+ })
+ }
+
+ for(let i = 0; i < res.length; i++){
+ let parentId=res[i].parentMenuId;
+ if(parentId==null){
+ actualData.push(res[i]);
+ }
+ }
+
+ $scope.treedata = actualData;
+
+ }).catch(err => {
+ $log.error('FunctionalMenuCtrl:getFunctionalMenu:: error ',err);
+ }).finally(()=> {
+ this.isLoadingTable = false;
+ });
+
+ };
+
+
+ let init = () => {
+ this.isLoadingTable = false;
+ this.functionalMenu = [];
+ getFunctionalMenu();
+ this.searchString = '';
+ };
+
+ this.filterByDropdownValue = item => {
+ if(this.filterByApp.value === ''){
+ return true;
+ }
+ return item.appName === this.filterByApp.value;
+ };
+
+ let getDialogTitle = (source) => {
+ switch (source) {
+ case 'edit':
+ return "Functional Menu - Edit";
+ case 'view':
+ return "Functional Menu - View";
+ case 'add':
+ return "Functional Menu - Add";
+ default:
+ return "Functional Menu";
+ }
+ }
+
+ $scope.reloadTreeStructure = (selectedItem,source) => {
+ getFunctionalMenu();
+ };
+ $scope.openMenuDetailsModal = (selectedItem,source) => {
+ let data = null;
+ let selectedMenuDetails = null;
+ console.log('selectedItem: ', selectedItem);
+
+ functionalMenuService.getMenuDetails(selectedItem.menuId)
+ .then(function( resp ){
+ selectedMenuDetails = resp;
+ $log.info('FunctionalMenuCtrl::openMenuDetailsModal: getMenuDetails: ', resp );
+
+ if(selectedItem){
+ data = {
+ menuItem: {menu: _.clone(selectedItem),menuDetails:_.clone(selectedMenuDetails)},
+ source: source,
+ title: getDialogTitle(source)
+ }
+ }
+ ngDialog.open({
+ templateUrl: 'app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html',
+ controller: 'MenuDetailsModalCtrl',
+ controllerAs: 'functionalMenuDetails',
+ data: data
+ }).closePromise.then(needUpdate => {
+ if(needUpdate.value === true){
+ $log.debug('FunctionalMenuCtrl::openMenuDetailsModal: updating table data...');
+ if(source=="edit")
+ init();
+ }
+ });
+ });
+ };
+
+
+ $scope.createNewMenuItem = (selectedItem,source) => {
+
+ if(selectedItem != null && selectedItem.getLevel() >= 4){
+ confirmBoxService.showInformation('You are not allowed to have a menu item at a level greater than 4.').then(isConfirmed => {
+
+ });
+ return ;
+ }
+
+ let data = null;
+ let selectedMenuDetails = null;
+ functionalMenuService.getMenuDetails(selectedItem.menuId)
+ .then(function( resp ){
+ selectedMenuDetails = resp;
+
+ if((selectedItem.children==null || !selectedItem.children.length>0) &&
+ (!!selectedMenuDetails.url || !!selectedMenuDetails.appid || !!selectedMenuDetails.roles)){
+ confirmBoxService.showInformation('Warning: the child menu item "' + selectedItem.name + '" is already configured with an application. You can create a new mid-level menu item, and move this item under it.').then(isConfirmed => {
+ return;
+ });
+ }else{
+ if(selectedItem){
+ data = {
+ menuItem: {menu: _.clone(selectedItem)},
+ source:source,
+ title: getDialogTitle(source)
+ }
+ }
+
+ ngDialog.open({
+ templateUrl: 'app/views/functionalMenu/functionalMenu-dialog/menu-details.modal.html',
+ controller: 'MenuDetailsModalCtrl',
+ controllerAs: 'functionalMenuDetails',
+ data: data
+ }).closePromise.then(needUpdate => {
+ if(needUpdate.value === true){
+ $log.debug('FunctionalMenuCtrl::getMenuDetails: updating table data...');
+ init();
+ }
+ });
+ }
+ });
+ };
+
+ $scope.deleteMenuItem = (selectedItem,source) => {
+ $log.info('FunctionalMenuCtrl:deleteMenuItem:: delete selectedItem: ', selectedItem);
+
+ if(selectedItem.children!=null && selectedItem.children.length>0){
+ confirmBoxService.showInformation('You are not allowed to delete a menu item that has children. You can only delete leaf menu items.').then(isConfirmed => {
+
+ });
+ }else{
+ confirmBoxService.deleteItem(selectedItem.name).then(isConfirmed => {
+ if(isConfirmed){
+ $log.info('FunctionalMenuCtrl:deleteMenuItem:: Deleting Menu Item :: name: '+selectedItem.name+'; menuId: '+selectedItem.menuId);
+ $log.info('FunctionalMenuCtrl:deleteMenuItem:: selectedItem: ', selectedItem);
+
+ functionalMenuService.deleteMenuItem(selectedItem.menuId).then(() => {
+ $log.info('FunctionalMenuCtrl:deleteMenuItem:: Removed Menu Item :: '+selectedItem.name);
+ init();
+ }).catch(err => {
+ $log.error(err);
+ });
+ }
+ }).catch(err => {
+ $log.error(err);
+ });
+ }
+ };
+
+ init();
+ }
+ }
+ FunctionalMenuCtrl.$inject = ['$log', 'functionalMenuService','$scope', 'ngDialog', 'confirmBoxService'];
+ angular.module('ecompApp').controller('FunctionalMenuCtrl', FunctionalMenuCtrl);
+
+ angular.module('ecompApp').directive('jqTree', ['functionalMenuService','$log','confirmBoxService',function(functionalMenuService,$log,confirmBoxService){
+ return {
+ templateUrl: 'jqtree-tmpl.html',
+ link: function(scope, el, attrs){
+
+ var $jqTree = el.find('#jqTree').tree({
+ data: scope.treedata,
+ autoOpen: false,
+ dragAndDrop: true,
+ onCreateLi: function(node, $li) {
+ $li.attr('id', node.id.replace(/\s+/g,"_"));
+ }
+ });
+
+ el.find('#jqTree').bind('tree.move', function(event){
+ event.preventDefault();
+ console.log('moved_node', event.move_info.moved_node);
+ console.log('target_node', event.move_info.target_node);
+ console.log('position', event.move_info.position);
+ console.log('previous_parent', event.move_info.previous_parent);
+
+
+
+ if(event.move_info.target_node != null &&
+ ((event.move_info.position == 'after' && event.move_info.target_node.getLevel() > 4) ||
+ (event.move_info.position == 'inside' && event.move_info.target_node.getLevel() > 3))){
+ confirmBoxService.showInformation('You are not allowed to have a menu item at a level greater than 4.').then(isConfirmed => {
+
+ });
+ return ;
+ }
+
+ var confMsg = 'Are you sure you want to move "'+event.move_info.moved_node.name+'" ?';
+ if ((event.move_info.position == "inside") && (event.move_info.target_node.url != "")) {
+ confMsg = 'Warning: You are moving "'+event.move_info.moved_node.name+'" under "'+event.move_info.target_node.name+'", which has application information associated with it. This will cause all the application information from "'+event.move_info.target_node.name+'" to be deleted.';
+ }
+ confirmBoxService.moveMenuItem(confMsg).then(isConfirmed => {
+ if(isConfirmed){
+ var new_column = event.move_info.target_node.column;
+ var old_column = event.move_info.moved_node.column;
+ if ((event.move_info.moved_node.parentMenuId !=
+ event.move_info.target_node.parentMenuId) ||
+ (new_column < old_column)
+ ) {
+ new_column += 1;
+ }
+ var activeMenuItem = {
+ menuId:event.move_info.moved_node.menuId,
+ column:new_column,
+ text:"",
+ parentMenuId:event.move_info.target_node.parentMenuId,
+ url:"",
+ appid: null,
+ roles:null
+ };
+
+ if (event.move_info.position == "inside") {
+ console.log("special case: target_node is parent");
+ activeMenuItem.column = 1;
+ activeMenuItem.parentMenuId = event.move_info.target_node.menuId;
+ }
+
+ functionalMenuService.saveEditedMenuItem(activeMenuItem)
+ .then(() => {
+ $log.debug(' Menu Item moved');
+ scope.reloadTreeStructure();
+ }).catch(err => {
+ $log.error(err);
+ }).finally(()=>{
+ });
+ }
+ }).catch(err => {
+ $log.error(err);
+ });
+ });
+
+
+ $jqTree.jqTreeContextMenu(el.find('ul.dropdown-menu'), {
+ "view": function (node) {scope.openMenuDetailsModal(node,'view'); },
+ "edit": function (node) {scope.openMenuDetailsModal(node,'edit'); },
+ "delete": function (node) { scope.deleteMenuItem(node,'delete') },
+ "add": function (node) { scope.createNewMenuItem(node,'add') }
+ });
+
+ scope.$watch('treedata', function(oldValue, newValue){
+ if(oldValue !== newValue){
+ console.log('FunctionalMenuCtrl:: Tree value has changed in some way');
+ $jqTree.tree('loadData', scope.treedata);
+ $jqTree.tree('reload', function() {
+ console.log('FunctionalMenuCtrl:: Tree is reloaded');
+ });
+ }
+ })
+ }
+ }
+ }]);
+
+})();
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.less b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.less
new file mode 100644
index 00000000..24a91287
--- /dev/null
+++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.less
@@ -0,0 +1,70 @@
+/*-
+ * ================================================================================
+ * eCOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ================================================================================
+ */
+ .functional-admin-page-main{
+ .bg_w;
+ position: @page-main-position;
+ top: @page-main-top;
+ left: @page-main-left;
+ right: @page-main-right;
+ bottom: @page-main-bottom;
+ padding-top: @padding-top;
+ overflow-y: @page-main-overflow-y;
+ padding-left: @padding-left-side;
+ .u16r;
+
+ .functional-admin-container {
+ .content_justify;
+ position: relative;
+ padding: 0 0 32px;
+ width: 1170px;
+
+ .functional-admin-home-title {
+ .a24r;
+ padding-bottom: 20px;
+ .content_justify;
+ }
+ .tree{
+ }
+ .functional-admin-button-container {
+ padding-top: 10px;
+ .btn-blue{
+ height: 35px;
+ width: 140px;
+ }
+ }
+ }
+ .error-text {
+ width: 1170px;
+ margin: auto;
+ padding: 20px;
+ left: 20px;
+ font-weight: bold;
+ font-size: 16px;
+ text-align: left;
+ color: @err;
+ background-color: @u;
+
+ .error-help {
+ color: @o;
+ font-weight: normal;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.tpl.html b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.tpl.html
new file mode 100644
index 00000000..a04cfe4c
--- /dev/null
+++ b/ecomp-portal-FE/client/app/views/functionalMenu/functionalMenu.tpl.html
@@ -0,0 +1,48 @@
+<!--
+ ================================================================================
+ eCOMP Portal
+ ================================================================================
+ Copyright (C) 2017 AT&T Intellectual Property
+ ================================================================================
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ================================================================================
+ -->
+<div class="w-ecomp-main">
+ <div class="w-ecomp-main-container">
+ <div class="functional-admin-page-main" id="contentId">
+ <div class="functional-admin-container">
+ <div id="functional-admin-home-title" class="functional-admin-home-title">Edit Functional Menu</div>
+ <div id="tree1">
+ <div id="Service_Creation"></div>
+ </div>
+ <div id="jq-tree-div" jq-tree class="tree"></div>
+ <script type="text/ng-template" id="jqtree-tmpl.html">
+ <div id="jqTree"></div>
+ <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
+ <li id="functional-menu-view-li"><a id="functional-menu-view-href" ng-href="#view"><i class="ion-eye"></i> View</a></li>
+ <li class="divider"></li>
+ <li id="functional-menu-add-li"><a id="functional-menu-add-href" ng-href="#add"><i class="ion-plus-round"></i> Add</a></li>
+ <li class="divider"></li>
+ <li id="functional-menu-edit-li"><a id="functional-menu-edit-href" ng-href="#edit"><i class="ion-edit"></i> Edit</a></li>
+ <li class="divider"></li>
+ <li id="functional-menu-delete-li"><a id="functional-menu-delete-href" ng-href="#delete"><i class="ion-trash-b"></i> Delete</a></li>
+ </ul>
+ </script>
+ <div class="functional-admin-button-container">
+ <button class="btn-blue" ng-click="functionalMenu.regenerateFunctionalMenuAncestors()">Regenerate Menu</button>
+ <span class="n16r">Click when you are done with your changes</span>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/ecomp-portal-FE/client/app/views/functionalMenu/jqTreeContextMenu.js b/ecomp-portal-FE/client/app/views/functionalMenu/jqTreeContextMenu.js
new file mode 100644
index 00000000..21e8454d
--- /dev/null
+++ b/ecomp-portal-FE/client/app/views/functionalMenu/jqTreeContextMenu.js
@@ -0,0 +1,192 @@
+/*-
+ * ================================================================================
+ * eCOMP Portal
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ================================================================================
+ */
+(function ($) {
+ if (!$.fn.tree) {
+ throw "Error jqTree is not loaded.";
+ }
+
+ $.fn.jqTreeContextMenu = function (menuElement, callbacks) {
+
+ var self = this;
+ var $el = this;
+
+ var $menuEl = menuElement;
+
+ var nodeToDisabledMenuItems = {};
+
+ $menuEl.hide();
+
+ $el.bind("contextmenu", function (e) {
+ e.preventDefault();
+ return false;
+ });
+
+ $el.bind('tree.contextmenu', function (event) {
+ var x = event.click_event.pageX;
+ var y = event.click_event.pageY;
+ var yPadding = 5;
+ var xPadding = 5;
+ var menuHeight = $menuEl.height();
+ var menuWidth = $menuEl.width();
+ var windowHeight = $(window).height();
+ var windowWidth = $(window).width();
+
+ if (menuHeight + y + yPadding > windowHeight) {
+ y = y - menuHeight;
+ }
+ if (menuWidth + x + xPadding > windowWidth) {
+ x = x - menuWidth;
+ }
+
+ if (Object.keys(nodeToDisabledMenuItems).length > 0) {
+ if (event.node.name in nodeToDisabledMenuItems) {
+ var nodeName = event.node.name;
+ var items = nodeToDisabledMenuItems[nodeName];
+ if (items.length === 0) {
+ $menuEl.find('li').addClass('disabled');
+ $menuEl.find('li > a').unbind('click');
+ } else {
+ $menuEl.find('li > a').each(function () {
+ $(this).closest('li').removeClass('disabled');
+ var hrefValue = $(this).attr('href');
+ var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length)
+ if ($.inArray(value, items) > -1) {
+ $(this).closest('li').addClass('disabled');
+ $(this).unbind('click');
+ }
+ });
+ }
+ } else {
+ $menuEl.find('li.disabled').removeClass('disabled');
+ }
+ }
+
+ $menuEl.show();
+
+ $menuEl.offset({ left: x, top: y });
+
+ var dismissContextMenu = function () {
+ $(document).unbind('click.jqtreecontextmenu');
+ $el.unbind('tree.click.jqtreecontextmenu');
+ $menuEl.hide();
+ }
+
+ $(document).bind('click.jqtreecontextmenu', function () {
+ dismissContextMenu();
+ });
+
+ $el.bind('tree.click.jqtreecontextmenu', function (e) {
+ dismissContextMenu();
+ });
+
+ var selectedNode = $el.tree('getSelectedNode');
+ if (selectedNode !== event.node) {
+ $el.tree('selectNode', event.node);
+ }
+
+ var menuItems = $menuEl.find('li:not(.disabled) a');
+ if (menuItems.length !== 0) {
+ menuItems.unbind('click');
+ menuItems.click(function (e) {
+ e.stopImmediatePropagation();
+ dismissContextMenu();
+ var hrefAnchor = e.currentTarget.attributes.href.nodeValue;
+ var funcKey = hrefAnchor.slice(hrefAnchor.indexOf("#") + 1, hrefAnchor.length)
+ var callbackFn = callbacks[funcKey];
+ if (callbackFn) {
+ callbackFn(event.node);
+ }
+ return false;
+ });
+ }
+ });
+
+ this.disable = function () {
+ if (arguments.length === 0) {
+ $menuEl.find('li:not(.disabled)').addClass('disabled');
+ $menuEl.find('li a').unbind('click');
+ nodeToDisabledMenuItems = {};
+ } else if (arguments.length === 1) {
+ var items = arguments[0];
+ if (typeof items !== 'object') {
+ return;
+ }
+ $menuEl.find('li > a').each(function () {
+ var hrefValue = $(this).attr('href');
+ var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length)
+ if ($.inArray(value, items) > -1) {
+ $(this).closest('li').addClass('disabled');
+ $(this).unbind('click');
+ }
+ });
+ nodeToDisabledMenuItems = {};
+ } else if (arguments.length === 2) {
+ var nodeName = arguments[0];
+ var items = arguments[1];
+ nodeToDisabledMenuItems[nodeName] = items;
+ }
+ };
+
+ this.enable = function () {
+ if (arguments.length === 0) {
+ $menuEl.find('li.disabled').removeClass('disabled');
+ nodeToDisabledMenuItems = {};
+ } else if (arguments.length === 1) {
+ var items = arguments[0];
+ if (typeof items !== 'object') {
+ return;
+ }
+
+ $menuEl.find('li > a').each(function () {
+ var hrefValue = $(this).attr('href');
+ var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length)
+ if ($.inArray(value, items) > -1) {
+ $(this).closest('li').removeClass('disabled');
+ }
+ });
+
+ nodeToDisabledMenuItems = {};
+ } else if (arguments.length === 2) {
+ var nodeName = arguments[0];
+ var items = arguments[1];
+ if (items.length === 0) {
+ delete nodeToDisabledMenuItems[nodeName];
+ } else {
+ var disabledItems = nodeToDisabledMenuItems[nodeName];
+ for (var i = 0; i < items.length; i++) {
+ var idx = disabledItems.indexOf(items[i]);
+ if (idx > -1) {
+ disabledItems.splice(idx, 1);
+ }
+ }
+ if (disabledItems.length === 0) {
+ delete nodeToDisabledMenuItems[nodeName];
+ } else {
+ nodeToDisabledMenuItems[nodeName] = disabledItems;
+ }
+ }
+ if (Object.keys(nodeToDisabledMenuItems).length === 0) {
+ $menuEl.find('li.disabled').removeClass('disabled');
+ }
+ }
+ };
+ return this;
+ };
+} (jQuery));