Portal Development Help - View All button

G24
Kilo Sage

Hello Smart and Helpful People...  I'm pretty terrible at Portal Development, and I don't have 4 weeks to relearn it.  Could someone possibly guide me through a small change???

 

When our portal (employee center) loads, and someone navigates to "HR Solutions", there is a "View All" button.  It looks like this:

1.png

 

Then, when the user clicks on that button, it disappears and is replaced by the two remaining "topics" like so:

2.png

 

We hate this behavior, and we want for the "HR Solutions topics" section to be expanded by default.  How can this be achieved?

 

When I Ctrl Right Click the space to the left of the View All button and I choose "Instance in Page Editor", I have the following:

3.png

 

Body HTML Template:

 

<div class="sub-topics-widget-container {{data.isMobileApp ? 'container-mobile' : ''}}">
  <div ng-class="data.isMobileApp? 'browse-elevation-mobile': 'browse-elevation'" ng-if="data.subTopics && data.subTopics.length > 0">
		<h3>{{::data.subTopicHeader}}</h3>
    <div class="main-container">
      <div class="subtopics-container" ng-style="c.getSubtopicsContainerStyle()">
        <div ng-repeat="item in data.subTopics track by $index">
          <a id="subtopic-{{$index}}" ng-attr-tabindex="{{c.isHidden($index) ? -1 : 0}}" ng-href="{{item.link}}&&in_context=true" class="subtopics break-word" ng-class="{ 'center-aligned' : options.show_topic_icon == 'false' || !item.icon}" aria-label="{{item.name}}">
            <img ng-if="options.show_topic_icon && item.icon" ng-src="{{item.icon}}" class="item-image"/>
            <span ec-multiline-ellipsis-tooltip ec-ellipsis-tooltip-title="{{::item.name}}" class="item-name">{{item.name}}</span>
          </a>
        </div>
      </div>
      <div class="show-more" ng-if="!c.data.viewAllMode && c.viewAllActive()">
        <button class="subtopics btn btn-default" ng-click="c.viewAll($event)" ng-keypress='c.viewAll($event)' aria-label="{{::data.showMoreData}}">
          {{::data.showMoreData}}
        </button>
      </div>
    </div>
	</div>
</div>

 

 

CSS:

 

$sp-space--xxs: 2px !default;
$sp-space--xs : 4px !default;
$sp-space--sm : 8px !default;
$sp-space--md : 12px !default;
$sp-space--lg : 16px !default;
$sp-space--xl : 24px !default;

$text-primary : #181A1F !default;

$font-size-small : 14px !default;
$font-size-base : 16px !default;
$headings-font-weight: 600 !default;

$background-primary : #ffffff !default;
$background-secondary : #f6f6f8 !default; 
$background-tertiary : #F0F1F5 !default;

$border-secondary : #ACB2BE !default;
$border-tertiary : #DADDE2 !default;

$sp-panel-box-shadow : 0 4px 8px 0 rgba(23,40,52,0.08) !default;

$divider: #F6F7F7 !default;

.sub-topics-widget-container {
  
  .browse-elevation {
    background: $background-primary;
    padding: 10px;
    margin: $sp-space--xl $sp-space--lg;
    border-radius: $border-radius-large;
    -webkit-box-shadow: $sp-panel-box-shadow;
    box-shadow: $sp-panel-box-shadow;

    h3 {
      padding-left: 14px;
      margin-top: 10px;
      word-break: break-word;
    }
  }
  
  .main-container {
    display: flex;
    padding: 0.2rem 1rem 0 1rem;
    .subtopics-container {
      position: relative;
      display: flex;
      flex-flow: wrap;
      height: 60px;
      overflow: hidden;
      padding-top: $sp-space--xs;
      padding-left: $sp-space--xs;
      >div {
        padding-right: 10px;
        padding-bottom: 10px;
        .subtopics:hover {
          box-shadow: 0rem 0.2rem 1rem #E5E5E5;
        }
        .center-aligned {
          justify-content: center;
          text-align: center;
        }
        .item-image {
          max-width: 28px;
          height: 28px;
          flex-shrink: 0;
          margin-right: $sp-space--sm;
        }
        .item-name {
          color: $text-primary;
          overflow: hidden;
          line-height: normal;
          display: -webkit-box;
          -webkit-line-clamp: 2;
          -webkit-box-orient: vertical;
          word-break: break-word;
          font-size: $font-size-small;
          font-weight: $headings-font-weight;
        }
        /* IE 10-11 specific Class to override */
        @media screen and (-ms-high-contrast: active),
        (-ms-high-contrast: none) {
          .item-name {
            white-space: nowrap;
            text-overflow: ellipsis;
            word-wrap: break-word;
          }
        }
      }
    }
    .subtopics {
      background: $background-primary;
      border: 1px solid $border-tertiary;
      border-radius: 4px !important;
      height: 50px;
      align-items: center;
      display: flex;
      min-width: 104px;
      max-width: 184px;
      padding-right: $sp-space--md;
      padding-left: $sp-space--md;
    }
    .show-more {
      padding-top: .4rem;
      margin-bottom: 10px;
      .btn {
        background: $background-primary;
        color: $text-primary;
        border-color: $border-tertiary;
        justify-content: center;
      }
      .btn:hover {
        background: $background-secondary;
      }
      .btn:active {
        background: $background-tertiary;
      }
    }
  }
  
  .browse-elevation-mobile {
    padding: 0 1rem;
    background: $background-primary;
    border-bottom: 12px solid $divider;
    padding-bottom: 14px;
    h3 {
      font-size: 20px !important;
      font-weight: bold;
      word-break: break-word;
    }
    .main-container {
      padding: $sp-space--xxs 0 0 0;
      .subtopics-container{
        >div{
          .item-name {
            font-size: $font-size-base;
            color: $text-color;
          }
        }
      }
      .show-more {
        .btn {
          color: $text-color;
        }
      }
    }
  }
  @media (max-width: 500px) {
    .main-container {
      flex-direction: column;
      .subtopics-container {
        > div {
          .item-image {
            margin: 0 $sp-space--sm;
          }
          .item-name {
            color: #333E3F;
          }
          .center-aligned {
            .item-name{
              padding-left: $sp-space--lg;
            }
          }
        }
      }
      .subtopics {
        padding-left: 0;
      }
      .show-more {
        .btn{
          padding-left: $sp-space--md;
          color: #333E3F;
        }
        align-self: center;
      }
    }
  }

}

 

 

Server Script:

 

(function() {
    data.subTopics = [];
    data.offset = 0;
    data.limit = 0;
    data.showMore = false;
    data.lastTopic = true;
    data.showMoreData = gs.getMessage("View all");
    data.isMobileApp = $sp.getParameter('view') === 'mobile';
    var fetchedSubTopics = [];
    data.topicId = (input && input.topic_id) || options.topic_id || $sp.getParameter("topic_id");
    data.subTopicHeader = gs.getMessage("{0} topics", getTopicName(data.topicId));
    var urlEnabled = gs.getProperty("sn_ex_sp.enable.image.url.support");

    function getTopicName(topicId) {
        try {
            var topicJs = new sn_taxonomy.Topic(topicId);
            return topicJs.getName();
        } catch (ex) {
            gs.error(gs.getMessage("Invalid Topic Id."));
        }

    }

    // Initial topic fetch on the basis of topic adjustments
    if (input && input.action === "getInitSubTopics") {
        var fetchLimit = input.topicLimit + 2;
        try {
            fetchedSubTopics = fetchSubTopics(input.topicId, 0, fetchLimit);
            if (fetchedSubTopics.length > input.topicLimit) {
                data.lastTopic = false;
            }
            data.subTopics = fetchedSubTopics;
        } catch (ex) {
            gs.addInfoMessage(gs.getMessage("You are either not authorized or record is not valid."));
        }
    }

    // on click of view all fetching all topics
    if (input && input.action === "viewAll") {
        data.showMore = false;
        data.subTopics = input.subTopics;
        if (!input.lastTopic) {
            fetchedSubTopics = fetchSubTopics(input.topicId, input.offset, 0);
            data.subTopics = data.subTopics.concat(fetchedSubTopics);
        }
    }


    function fetchSubTopics(topicId, startWindow, endWindow) {
        try {
            var topicJs = new sn_taxonomy.Topic(topicId);
            var childTopics = topicJs.getChildTopics(true, data.isMobileApp, endWindow, startWindow);
            var topics = childTopics.topics;
            var topicUtil = new sn_ex_sp.TopicPageUtil();
            for (var i = 0; i < topics.length; i++) {
                if (options.show_topic_icon === 'true') {
                    var icon;
                    if(urlEnabled && urlEnabled==="true")
                      icon = topicUtil.getIcon(topics[i].sys_id);
                    else
                      icon = sn_taxonomy.Topic.getIcon(topics[i].sys_id);

                    if (icon && icon.trim()) {
                        topics[i].icon = icon;
                    } else {
                        topics[i].icon = topicUtil.fetchDefaultIconImage();
                    }
                }
                var pageToRedirect = topics[i].template && topics[i].template.length > 0 ? topics[i].template : 'emp_taxonomy_topic';
                topics[i].link = '?id='+ pageToRedirect +'&topic_id=' + topics[i].sys_id;
                if (data.isMobileApp) {
                    topics[i].link = topics[i].link + '&view=mobile';
                }
            }
            data.limit = childTopics.limit;
            data.offset = childTopics.offset;
            return topics;
        } catch (ex) {
            gs.error(gs.getMessage("Invalid Topic Id."));
        }

    }
})();

 

 

Client Controller:

 

api.controller = function($scope, $window) {
    /* widget controller */
    var c = this;
    c.data.viewAllMode = false;
    var SMALL_DEVICE_WIDTH = 500;
    var SUBTOPICS_BOX_HEIGHT = 50 + 10; // height + padding
    var SUBTOPICS_CONTAINER_HEIGHT_PADDING = 4;
    var pixelToRem = 10;	
    if(c.data.isMobileApp) {	
      pixelToRem = 16;	
    }
    
    // HTML font size on different devices which is used for conversion
    var perDevicePixelToRem = $('html').css('font-size');
    perDevicePixelToRem = parseFloat(perDevicePixelToRem, 10);
    
    // If pixelToRem == perDevicePixelToRem value will remain same, else will convert based on device
    SUBTOPICS_BOX_HEIGHT = (SUBTOPICS_BOX_HEIGHT / pixelToRem) * perDevicePixelToRem;
    SUBTOPICS_CONTAINER_HEIGHT_PADDING = (SUBTOPICS_CONTAINER_HEIGHT_PADDING / pixelToRem) * perDevicePixelToRem;
    var MIN_HEIGHT_FOR_SMALL_DEVICE = 3 * SUBTOPICS_BOX_HEIGHT; // 3 rows of subtopics

    c.viewAll = function(event) { 
        event.preventDefault(); // prevent default scroll behavior on space
        if (event.type == 'keypress' && (event.which != '13' && event.which != '32'))
          return;
        c.data.action = "viewAll";
        var subtopicsContainer = $(".subtopics-container");
        if (subtopicsContainer) {
          subtopicsContainer.height("auto");
        }
        c.data.viewAllMode = true;
        var subtopics = $('.subtopics');
        // Update focus only when space or enter key is pressed
        if (event.which == '13' || event.which == '32') {
          for(var i = 0;i < subtopics.length; i++) {
            if(subtopics[i].getAttribute('tabindex') === '-1') {
              subtopics[i].focus();
              break;
            }
          }
        }
        $('.subtopics').removeAttr("tabindex");
        c.server.update().then(function() {
            c.data.action = "";
        });
    };

    c.getSubtopicsContainerStyle = function() {
        var style = {
            "height": "auto"
        };
        var subtopicsContainer = $(".subtopics-container");
        if (subtopicsContainer) {
            if (c.data.viewAllMode) {
                return style;
            } else {
                var subtopicsBoxHeightCSS = 50 + 10; // height + padding
                var subtopicsListHeight = subtopicsContainer.prop("scrollHeight");
                if ($window.innerWidth <= SMALL_DEVICE_WIDTH && subtopicsListHeight > MIN_HEIGHT_FOR_SMALL_DEVICE + SUBTOPICS_CONTAINER_HEIGHT_PADDING) {
                    style.height = ( 2 * subtopicsBoxHeightCSS ) / pixelToRem + "rem"; 
                    return style;
                } else if ($window.innerWidth > SMALL_DEVICE_WIDTH) {
                    style.height = subtopicsBoxHeightCSS / pixelToRem + "rem"; 
                    return style;
                } else {
                    return style;
                }
            }
        }
    };

    c.isHidden = function(index) {
        var subtopicsContainer = $(".subtopics-container");
        var subtopicsContainerHeight = subtopicsContainer.height();
        var subtopic = $("#subtopic-" + index);
        if (subtopic && subtopic.position() && subtopic.position().top) {
            return subtopic.position().top > subtopicsContainerHeight;
        }
        return true;
    };

    c.viewAllActive = function() {
        var subtopicsContainer = $(".subtopics-container");
        if (subtopicsContainer) {
            var subtopicsListHeight = subtopicsContainer.prop("scrollHeight");
            if ($window.innerWidth <= SMALL_DEVICE_WIDTH) {
                return subtopicsListHeight > MIN_HEIGHT_FOR_SMALL_DEVICE + SUBTOPICS_CONTAINER_HEIGHT_PADDING;
            } else {
                return subtopicsListHeight > SUBTOPICS_BOX_HEIGHT + SUBTOPICS_CONTAINER_HEIGHT_PADDING;
            }
        }
        return false;
    };

    c.server.get({
        topicLimit: 15,
        action: "getInitSubTopics",
        topicId: c.data.topicId
    }).then(function(response) {
        if (response) {
            c.data.subTopics = response.data.subTopics;
            c.data.showMore = response.data.showMore;
            c.data.lastTopic = response.data.lastTopic;
            c.data.offset = response.data.offset;
            c.data.action = "";
        }
    });

    var resizeWindow = function() {
        $scope.$apply();
    };
    var appWindow = angular.element($window);
    appWindow.bind('resize', _.debounce(resizeWindow, 300));

};

 

 

Can someone please explain the easiest or most straight-forward way that we can have this widget load in the Expanded state?  Much appreciated.

3 REPLIES 3

Juhi Poddar
Kilo Patron

Hello @G24 

The current widget is primarily designed with a focus on the logic for the "View All" button. Implementing your desired functionality will require significant modifications. Therefore, I recommend creating a new widget and implementing the required logic from scratch.

The good news is that much of the complexity in the existing code stems from the "View All" button. If this button isn’t needed, the new logic will be much simpler to build. You can also use the existing widget as a reference while developing the new one.

Hope this helps!

 

"If you found my answer helpful, please like and mark it as an "accepted solution". It helps future readers to locate the solution easily and supports the community!"

 

Thank You
Juhi Poddar

Oh, God.  I was really hoping to NOT have to build a brand new widget.  But thanks for responding.