Activating the three dot loading indicator

shawnbaar
Giga Expert

Good afternoon,

At some point, the three dots that flash whenever a user navigates between portal pages has been disabled.  Does anyone know where/what I need to configure to re-enable it?  In the Header Menu widget I am able to see the Body HTML the following code:

find_real_file.png

And in the Client Controller, I see this:

find_real_file.png

I am pretty new to bootstrap stuff with the portal so I am not sure why the three dots do not appear on the portal pages when navigating between pages.  Any help/guidance would be greatly appreciated.

Thanks,

Shawn

1 ACCEPTED SOLUTION

Allen Andreas
Administrator
Administrator

My header widget may have been tweaked, so take care in looking at what you need, but I'll post mine and it's working for me:

 

Body HTML Template

<ul class="nav navbar-nav" aria-label="${Header menu}">
  <div class="header-loader" ng-show="loadingIndicator">
    <div class="hidden-xs sp-loading-indicator la-sm">
      <div></div>
      <div></div>
      <div></div>
    </div>
  </div>
  <li ng-repeat="item in visibleItems" ng-class="{dropdown: item.items.length > 0, 'header-menu-item': true}" ng-include="'menuTemplate'"></li>
<!-- Wishlist menu -->
  <li ng-if="options.enable_wishlist && data.isLoggedIn && data.showWishlist" ng-show="!accessibilityEnabled" class="dropdown hidden-xs">
  	<a role="menuitem" href="javascript:void(0)"
       data-toggle="dropdown"
       id="wishlist-menu"
       title="${Your Wish List currently has} {{wishlistItemCount}} ${items}"
       aria-label="${Wish List}">
      <span ng-bind-html="'${Wish List}'" aria-hidden="true"></span>
      <span ng-if="wishlistItemCount > 0" aria-hidden="true" class="label label-as-badge label-primary sp-navbar-badge-count">{{wishlistItemCount}}</span>
		</a>
    <div class="dropdown-menu wishlist-menu">
      <sp-widget widget="data.wishlistWidget"></sp-widget>
    </div>
  </li>
  <li ng-if="options.enable_wishlist && data.isLoggedIn && data.showWishlist" class="dropdown" ng-class="{'visible-xs': !accessibilityEnabled}"  aria-label="${Your Wish List currently has} {{wishlistItemCount}} ${items}">
  	<a href="?id=sc_wishlist"
       title="${Wish List}"
       class="toggle-dropdown">
      <span ng-bind-html="'${Wish List}'" aria-hidden="true"></span>
      <span ng-if="wishlistItemCount > 0" aria-hidden="true" class="label label-as-badge label-primary sp-navbar-badge-count">{{wishlistItemCount}}</span>
		</a>
  </li>
  <!-- Shopping cart stuff -->
 <li ng-if="::options.enable_cart && data.isLoggedIn" ng-show="::!accessibilityEnabled" class="dropdown hidden-xs header-menu-item">
  	<a href
       data-toggle="dropdown"
       id="cart-dropdown"
       uib-tooltip-template="'item-added-tooltip.html'"
       tooltip-placement="bottom"
       tooltip-trigger="'none'"
       tooltip-is-open="$parent.itemAddedTooltipOpen"
       title="${Your shopping cart currently has} {{cartItemCount}} ${items}"
       aria-label="${Shopping cart}">
    	<i class="fa fa-shopping-cart" aria-hidden="true"></i>
      <span ng-bind-html="'${Cart}'" aria-hidden="true"></span>
      <span ng-if="cartItemCount > 0" aria-hidden="true" class="label label-as-badge label-primary sp-navbar-badge-count">{{cartItemCount}}</span>
		</a>
    <div class="dropdown-menu cart-dropdown">
      <sp-widget widget="data.cartWidget"></sp-widget>
    </div>
  </li>
  <li ng-if="::options.enable_cart && data.isLoggedIn" class="dropdown" ng-class="::{'visible-xs': !accessibilityEnabled}"  aria-label="${Your shopping cart currently has} {{cartItemCount}} ${items}">
  	<a href="?id=sc_cart"
       title="${Cart}"
       class="toggle-dropdown">
    	<i class="fa fa-shopping-cart" aria-hidden="true"></i>
      <span ng-bind-html="'${Cart}'" aria-hidden="true"></span>
      <span ng-if="cartItemCount > 0" aria-hidden="true" class="label label-as-badge label-primary sp-navbar-badge-count">{{cartItemCount}}</span>
	</a>
  </li>
</ul>
  

 

CSS

.header-loader {
	float: left;
  	width: 24px;
  	position: relative;
  	top: 24px;
}

.cart-dropdown, .wishlist-menu {
  width: 350px;
  padding: 0;
  z-index: 1000;
  border-top-left-radius: 4px !important;
  border-top-right-radius: 4px !important;

  ul {
    max-height: 300px;
    overflow: auto;
  }

  .subtotal {
    display: block;
  }

  .item-image {
    padding: 0;
    margin: 0;
    text-align: center;
    max-width:100%;
    height:auto;
  }
  label, p {
    padding: 0;
    margin: 0;
  }
  .media {
    padding: 0;
    margin: 0;
  }
  .media-left > a {
    display: block;
    width: 48px;
    max-width: 48px;
  }
  .media-body {
    label {
      font-weight: bold;
    }
  }
  li.media {
    border-top: 1px solid #cccccc;
    padding: 1rem;
  }
  .panel {
    margin: 0;
  }
  .panel .panel-body {
    padding: 0;
  }
  .btn-clear {
		color: #333;
    background-color: #fff;
  }
  p.quantity-price {
    padding-top: 0.5rem;
    span {
      color: $text-muted;
      padding-right: 0.5rem;
    }
  }
  .align-right {
  	text-align: right;
  }
}



.item-added-tooltip, wishlist-item-added-tooltip {
  width: 184px;
  font-size: 14px;
}

 

Server script:

(function(){
	// build menus
	var menu_id = $sp.getValue('sys_id'); // instance sys_id
	var gr = new GlideRecord('sp_instance_menu');
	gr.get(menu_id);
	data.menu = {};
	data.menu.name = gr.name.getDisplayValue();
	data.menu.items = $sp.getMenuItems(menu_id);

	data.isLoggedIn = GlideSession.get().isLoggedIn();
	data.showWishlist = new sn_sc.Catalog('' + $sp.getValue('sc_catalog')).isWishlistEnabled();
	if (data.isLoggedIn) {
		if (data.showWishlist)
			data.wishlistWidget = $sp.getWidget("sc_wishlist_cart", {wishlistTemplate: "small_wishlist.html", auto_update_wishlist:options.auto_update_wishlist});
		if (gs.getProperty("glide.sc.portal.use_cart_v2_header", "false") === "true")
			data.cartWidget = $sp.getWidget("sc-shopping-cart-v2", {cartTemplate: "small_shopping_cart_v2.html", auto_update_cart:options.auto_update_cart});
		else
			data.cartWidget = $sp.getWidget("sc-shopping-cart", {cartTemplate: "small_shopping_cart.html", auto_update_cart:options.auto_update_cart});
	}
})();

 

Client controller:

function ($scope, spUtil, $rootScope, $timeout, spAriaUtil) {
	$scope.loadingIndicator = $rootScope.loadingIndicator;
	$scope.cartItemCount = 0;
	$scope.wishlistItemCount = 0;
	$scope.itemAddedTooltipOpen = false;

	$scope.accessibilityEnabled = spAriaUtil.g_accessibility === "true";

	$scope.$on("$sp.service_catalog.cart.count", function($evt, count) {
		$scope.cartItemCount = count;
	});

	$scope.$on("$sp.service_catalog.wishlist.count", function($evt, count) {
		$scope.wishlistItemCount = count;
	});

	var cancelTooltipPromise;
	$scope.$on("$sp.service_catalog.cart.add_item", function() {
		$timeout.cancel(cancelTooltipPromise);

		$scope.itemAddedTooltipOpen = true;
		cancelTooltipPromise = $timeout(function() {
			$scope.itemAddedTooltipOpen = false;
		}, 3000);
	});

	$scope.$on('sp_loading_indicator', function(e, value) {
		$scope.loadingIndicator = value;
	});

	$scope.toggleCart = function() {
		$timeout.cancel(cancelTooltipPromise);
		$scope.itemAddedTooltipOpen = false;
		$timeout(function() {
			$("#cart-dropdown").dropdown("toggle");
		});
	};

	// PRB1108244: visibleItems array is used to improve keyboard nav 
	// in menu, refresh it as needed
	$scope.$watch('data.menu.items', function() {
		$scope.visibleItems = [];
		if ($scope.data.menu.items) {
			for (var i in $scope.data.menu.items) {
				var item = $scope.data.menu.items[i];
				if (item.items || (item.scriptedItems && item.scriptedItems.count >= 0))
					$scope.visibleItems.push(item);
			}
		}
	}, true);

	// Get list of record watchers
	var record_watchers = [];
	if ($scope.data.menu.items) {
		for(var i in $scope.data.menu.items) {
			var item = $scope.data.menu.items[i];
			if (item.type == 'scripted') {
				if (item.scriptedItems.record_watchers)
					record_watchers = record_watchers.concat(item.scriptedItems.record_watchers);
			}
			if (item.type == 'filtered') {
				record_watchers.push({'table':item.table,'filter':item.filter});
			}
		}
	}

	// Init record watchers
	for (var y in record_watchers){
		var watcher = record_watchers[y];
		spUtil.recordWatch($scope, watcher.table, watcher.filter);
	}
}

 

Link:

function(scope, elem) {
	$(elem).on('keydown','.header-menu-item',function(e){
		var target = e.target;
		if (target.localName == 'a') {
			if(e.keyCode == 37) {
				e.preventDefault();
				$(target).parents('li').removeClass('open');
				$(target).parents('li').prev('li').find('a').focus();
			} else if(e.keyCode == 39) {
				e.preventDefault();
				$(target).parents('li').removeClass('open');
				$(target).parents('li').next('li').find('a').focus();
				
			}
			if(e.keyCode == 9) {
				$(target).parents('li').removeClass('open');
			}
		}
		});
	}

 

Please mark reply as Helpful/Correct, if applicable. Thanks!


Please consider marking my reply as Helpful and/or Accept Solution, if applicable. Thanks!

View solution in original post

7 REPLIES 7

Allen Andreas
Administrator
Administrator

My header widget may have been tweaked, so take care in looking at what you need, but I'll post mine and it's working for me:

 

Body HTML Template

<ul class="nav navbar-nav" aria-label="${Header menu}">
  <div class="header-loader" ng-show="loadingIndicator">
    <div class="hidden-xs sp-loading-indicator la-sm">
      <div></div>
      <div></div>
      <div></div>
    </div>
  </div>
  <li ng-repeat="item in visibleItems" ng-class="{dropdown: item.items.length > 0, 'header-menu-item': true}" ng-include="'menuTemplate'"></li>
<!-- Wishlist menu -->
  <li ng-if="options.enable_wishlist && data.isLoggedIn && data.showWishlist" ng-show="!accessibilityEnabled" class="dropdown hidden-xs">
  	<a role="menuitem" href="javascript:void(0)"
       data-toggle="dropdown"
       id="wishlist-menu"
       title="${Your Wish List currently has} {{wishlistItemCount}} ${items}"
       aria-label="${Wish List}">
      <span ng-bind-html="'${Wish List}'" aria-hidden="true"></span>
      <span ng-if="wishlistItemCount > 0" aria-hidden="true" class="label label-as-badge label-primary sp-navbar-badge-count">{{wishlistItemCount}}</span>
		</a>
    <div class="dropdown-menu wishlist-menu">
      <sp-widget widget="data.wishlistWidget"></sp-widget>
    </div>
  </li>
  <li ng-if="options.enable_wishlist && data.isLoggedIn && data.showWishlist" class="dropdown" ng-class="{'visible-xs': !accessibilityEnabled}"  aria-label="${Your Wish List currently has} {{wishlistItemCount}} ${items}">
  	<a href="?id=sc_wishlist"
       title="${Wish List}"
       class="toggle-dropdown">
      <span ng-bind-html="'${Wish List}'" aria-hidden="true"></span>
      <span ng-if="wishlistItemCount > 0" aria-hidden="true" class="label label-as-badge label-primary sp-navbar-badge-count">{{wishlistItemCount}}</span>
		</a>
  </li>
  <!-- Shopping cart stuff -->
 <li ng-if="::options.enable_cart && data.isLoggedIn" ng-show="::!accessibilityEnabled" class="dropdown hidden-xs header-menu-item">
  	<a href
       data-toggle="dropdown"
       id="cart-dropdown"
       uib-tooltip-template="'item-added-tooltip.html'"
       tooltip-placement="bottom"
       tooltip-trigger="'none'"
       tooltip-is-open="$parent.itemAddedTooltipOpen"
       title="${Your shopping cart currently has} {{cartItemCount}} ${items}"
       aria-label="${Shopping cart}">
    	<i class="fa fa-shopping-cart" aria-hidden="true"></i>
      <span ng-bind-html="'${Cart}'" aria-hidden="true"></span>
      <span ng-if="cartItemCount > 0" aria-hidden="true" class="label label-as-badge label-primary sp-navbar-badge-count">{{cartItemCount}}</span>
		</a>
    <div class="dropdown-menu cart-dropdown">
      <sp-widget widget="data.cartWidget"></sp-widget>
    </div>
  </li>
  <li ng-if="::options.enable_cart && data.isLoggedIn" class="dropdown" ng-class="::{'visible-xs': !accessibilityEnabled}"  aria-label="${Your shopping cart currently has} {{cartItemCount}} ${items}">
  	<a href="?id=sc_cart"
       title="${Cart}"
       class="toggle-dropdown">
    	<i class="fa fa-shopping-cart" aria-hidden="true"></i>
      <span ng-bind-html="'${Cart}'" aria-hidden="true"></span>
      <span ng-if="cartItemCount > 0" aria-hidden="true" class="label label-as-badge label-primary sp-navbar-badge-count">{{cartItemCount}}</span>
	</a>
  </li>
</ul>
  

 

CSS

.header-loader {
	float: left;
  	width: 24px;
  	position: relative;
  	top: 24px;
}

.cart-dropdown, .wishlist-menu {
  width: 350px;
  padding: 0;
  z-index: 1000;
  border-top-left-radius: 4px !important;
  border-top-right-radius: 4px !important;

  ul {
    max-height: 300px;
    overflow: auto;
  }

  .subtotal {
    display: block;
  }

  .item-image {
    padding: 0;
    margin: 0;
    text-align: center;
    max-width:100%;
    height:auto;
  }
  label, p {
    padding: 0;
    margin: 0;
  }
  .media {
    padding: 0;
    margin: 0;
  }
  .media-left > a {
    display: block;
    width: 48px;
    max-width: 48px;
  }
  .media-body {
    label {
      font-weight: bold;
    }
  }
  li.media {
    border-top: 1px solid #cccccc;
    padding: 1rem;
  }
  .panel {
    margin: 0;
  }
  .panel .panel-body {
    padding: 0;
  }
  .btn-clear {
		color: #333;
    background-color: #fff;
  }
  p.quantity-price {
    padding-top: 0.5rem;
    span {
      color: $text-muted;
      padding-right: 0.5rem;
    }
  }
  .align-right {
  	text-align: right;
  }
}



.item-added-tooltip, wishlist-item-added-tooltip {
  width: 184px;
  font-size: 14px;
}

 

Server script:

(function(){
	// build menus
	var menu_id = $sp.getValue('sys_id'); // instance sys_id
	var gr = new GlideRecord('sp_instance_menu');
	gr.get(menu_id);
	data.menu = {};
	data.menu.name = gr.name.getDisplayValue();
	data.menu.items = $sp.getMenuItems(menu_id);

	data.isLoggedIn = GlideSession.get().isLoggedIn();
	data.showWishlist = new sn_sc.Catalog('' + $sp.getValue('sc_catalog')).isWishlistEnabled();
	if (data.isLoggedIn) {
		if (data.showWishlist)
			data.wishlistWidget = $sp.getWidget("sc_wishlist_cart", {wishlistTemplate: "small_wishlist.html", auto_update_wishlist:options.auto_update_wishlist});
		if (gs.getProperty("glide.sc.portal.use_cart_v2_header", "false") === "true")
			data.cartWidget = $sp.getWidget("sc-shopping-cart-v2", {cartTemplate: "small_shopping_cart_v2.html", auto_update_cart:options.auto_update_cart});
		else
			data.cartWidget = $sp.getWidget("sc-shopping-cart", {cartTemplate: "small_shopping_cart.html", auto_update_cart:options.auto_update_cart});
	}
})();

 

Client controller:

function ($scope, spUtil, $rootScope, $timeout, spAriaUtil) {
	$scope.loadingIndicator = $rootScope.loadingIndicator;
	$scope.cartItemCount = 0;
	$scope.wishlistItemCount = 0;
	$scope.itemAddedTooltipOpen = false;

	$scope.accessibilityEnabled = spAriaUtil.g_accessibility === "true";

	$scope.$on("$sp.service_catalog.cart.count", function($evt, count) {
		$scope.cartItemCount = count;
	});

	$scope.$on("$sp.service_catalog.wishlist.count", function($evt, count) {
		$scope.wishlistItemCount = count;
	});

	var cancelTooltipPromise;
	$scope.$on("$sp.service_catalog.cart.add_item", function() {
		$timeout.cancel(cancelTooltipPromise);

		$scope.itemAddedTooltipOpen = true;
		cancelTooltipPromise = $timeout(function() {
			$scope.itemAddedTooltipOpen = false;
		}, 3000);
	});

	$scope.$on('sp_loading_indicator', function(e, value) {
		$scope.loadingIndicator = value;
	});

	$scope.toggleCart = function() {
		$timeout.cancel(cancelTooltipPromise);
		$scope.itemAddedTooltipOpen = false;
		$timeout(function() {
			$("#cart-dropdown").dropdown("toggle");
		});
	};

	// PRB1108244: visibleItems array is used to improve keyboard nav 
	// in menu, refresh it as needed
	$scope.$watch('data.menu.items', function() {
		$scope.visibleItems = [];
		if ($scope.data.menu.items) {
			for (var i in $scope.data.menu.items) {
				var item = $scope.data.menu.items[i];
				if (item.items || (item.scriptedItems && item.scriptedItems.count >= 0))
					$scope.visibleItems.push(item);
			}
		}
	}, true);

	// Get list of record watchers
	var record_watchers = [];
	if ($scope.data.menu.items) {
		for(var i in $scope.data.menu.items) {
			var item = $scope.data.menu.items[i];
			if (item.type == 'scripted') {
				if (item.scriptedItems.record_watchers)
					record_watchers = record_watchers.concat(item.scriptedItems.record_watchers);
			}
			if (item.type == 'filtered') {
				record_watchers.push({'table':item.table,'filter':item.filter});
			}
		}
	}

	// Init record watchers
	for (var y in record_watchers){
		var watcher = record_watchers[y];
		spUtil.recordWatch($scope, watcher.table, watcher.filter);
	}
}

 

Link:

function(scope, elem) {
	$(elem).on('keydown','.header-menu-item',function(e){
		var target = e.target;
		if (target.localName == 'a') {
			if(e.keyCode == 37) {
				e.preventDefault();
				$(target).parents('li').removeClass('open');
				$(target).parents('li').prev('li').find('a').focus();
			} else if(e.keyCode == 39) {
				e.preventDefault();
				$(target).parents('li').removeClass('open');
				$(target).parents('li').next('li').find('a').focus();
				
			}
			if(e.keyCode == 9) {
				$(target).parents('li').removeClass('open');
			}
		}
		});
	}

 

Please mark reply as Helpful/Correct, if applicable. Thanks!


Please consider marking my reply as Helpful and/or Accept Solution, if applicable. Thanks!

shawnbaar
Giga Expert

Thank you for posting your code.  I must admit I was further stumped because we had mostly the exact same code.  It turns out that the color of the dots was the same as the color of the banner background.  The dots were working, I just couldn't see them.  Once we changed the color of the dots, everyone was happy.  As embarrassed as it might make me, I thought someone else might encounter something similar one day and need this reminder.

Ah, I'll note that as well if I come across someone else who has this problem too, haha. The small things usually is what gets us. Glad you got it straight. 🙂


Please consider marking my reply as Helpful and/or Accept Solution, if applicable. Thanks!

We have the same issue, where our header is white so the ... is not showing. Can you share where exactly you updated the color of the ... please. Thanks so much!