Displaying All Providers and All Authors separately in Susper Angular App

In Susper results are retrieved from a lots of providers and authors. Displaying all authors’ and providers’ list on result page make appearance of result section odd and more complex. In this blog, I will describe how we have separated the list of all providers and authors from main result page and displayed it on a lightbox.

Steps:

  • Making a black overlay for lightbox:

First we of all to display the results on a lightbox,we to have a black overlay for this we need a div element and inside it we need a closing button.

Clicking on the black overlay should toggle status of light box therefore we have binded click event with showMore() method.

<div id="fade_analytics" class="black_overlay" (click)='showMore()'><a class="closeX" id="closeX">&#10006;</a></div>
  • Creating a white content to display all Providers or Authors:

Now we need a white block to display all Providers or all Authors so after creating a black overlay in background we need a white foreground.

Therefore I have implemented a div element and put all the chart elements inside the div element so that it will be displayed on a white foreground on a translucent black background.

<div id="light_analytics" class="white_content_analytics">
<div class="show_more"><h2 class="heading"><b>Analytics</b></h2><div id="filtersearch" *ngFor="let nav of navigation$|async; let i = index"><div class="card-container" id="relate" *ngIf="nav.displayname =='Provider' || nav.displayname =='Authors'"><h3  class="related-searches" *ngIf="i===currentelement"><b>Top {{nav.displayname}}<span *ngIf="nav.displayname.slice(-1)!=='s'">s</span></b></h3>
<div style="display: block;cursor:pointer;cursor: hand;" *ngFor="let element of  ((i != currentelement)? (nav.elements | slice:0:0) :nav.elements)">
</div></div></div></div>

The code to display All providers and All authors are contained inside the   white block and the logic to display the each section is also implemented.

  • Showing only 50 results on result page and implementing a button to open all providers or authors in light box:

Currently we are displaying the top five providers and authors and we provide a button to show more providers and authors which then displays 50 more results and then we display an interactive button that toggles display of all authors and providers on a lightbox. To display 5 and 50 results we use slice pipe in angular. The button Show All Providers/Authors is binded with showMore() function which toggles lightbox.

<div style="display: block;cursor:pointer;cursor: hand;" *ngFor="let element of ((i != selectedelement)? (nav.elements | slice:0:5) :(nav.elements | slice:0:50) )">
<a [routerLink]="['/search']" [queryParams]="changequerylook(element.modifier,element)" *ngIf="element.name" href="#" [style.color]="themeService.linkColor">
{{element.name}} <span class="badge badge-info">{{element.count}}</span>
</a><a  *ngIf="!element.name" style="color: black;cursor: default" href="#" [style.color]="themeService.linkColor">
Undefined Author <span class="badge badge-info">{{element.count}}</span></a></div>
<button class="showMoreBtn" (click)="showMore()" *ngIf="selectedelement===i" [style.color]="themeService.linkColor">Show All {{nav.displayname}}<span *ngIf="nav.displayname.slice(-1)!=='s'">s</span></button>

 

  • Implementing the logic to display all results on white content:

Now we need to implement the logic to toggle lightbox to display All Providers and All Authors. This logic is implemented mainly in showMore() function which toggles the lightbox containing the All Providers and All Authors

showMore() { this.selectedelement = -1;
if (!this.showMoreAnalytics) { this.showMoreAnalytics = true; document.getElementById('light_analytics').style.display = 'block'; document.getElementById('fade_analytics').style.display = 'block'; } else { this.showMoreAnalytics = false;
document.getElementById('light_analytics').style.display = 'none';
document.getElementById('fade_analytics').style.display = 'none';}}

Here we use showMoreAnalytics variable to check whether the user has asked to show all Providers or Authors. We also make selectedelement variable to -1 to hide the long list of 50 Providers or Authors when Lightbox displays all the Providers or Author. Finally we use document object in javascript and select the DOM elements by their id and set their display property this shows and hides the lightbox on result page.

Resources

1.YaCy Advanced Search Parameters

http://www.yacy-websuche.de/wiki/index.php/En:SearchParameters

2.W3School lightbox

https://www.w3schools.com/howto/howto_js_lightbox.asp

 

Continue Reading

Adding ‘Scroll to Top’ in Loklak Search

It is really important for a Progressive Web Application like Loklak to be user friendly. To enhance the user experience and help user scroll up through the long list of results, a new ‘Scroll to Top’ feature has been added to Loklak.

Integration Process

The feature is built using HostListener and Inject property of Angular, which allows to use Window and Document functionalities similar to Javascript.

Adding HostListener

First step would be to import HostListener and Inject, and create property of document using with Inject.

import { HostListener, Inject } from ‘@angular/core’;
navIsFixed: boolean;
constructor(
    @Inject(DOCUMENT) private document: Document
) { }

 

Next step would be to create method to detect the current state of window, and scroll to the top of window.

@HostListener(‘window:scroll’, [])
onWindowScroll() {
    if (window.pageYOffset
        || document.documentElement.scrollTop
        || document.body.scrollTop > 100) {
                this.navIsFixed = true;
    } else if (this.navIsFixed && window.pageYOffset
        || document.documentElement.scrollTop
            || document.body.scrollTop < 10) {
                    this.navIsFixed = false;
            }
        } scrollToTop() {
            (function smoothscroll() {
                const currentScroll =
                    document.documentElement.scrollTop
                        || document.body.scrollTop;
            if (currentScroll > 0) {
            window.requestAnimationFrame(smoothscroll);
            window.scrollTo(0,
                currentScroll  (currentScroll / 5));
        }
    })();
}

 

The last step would be to add user interface part i.e. HTML and CSS component for the Scroll to Top feature.

Creating user interface

HTML

HTML portion contains a div tag with class set to CSS created and a button with click event attached to it to call the scrollToTop() method created above.

CSS

The CSS class corresponding to the div tag provides the layout of the button.

button {
   display: block;
   margin: 32px auto;
   font-size: 1.1em;
   padding: 5px;
   font-weight: 700;
   background: transparent;
   border: none;
   cursor: pointer;
   height: 40px;
   width: 40px;
   font-size: 30px;
   color: white;
   background-color: #d23e42;
   border-radius: 76px;
   &:focus {
       border: none;
       outline: none;
   }
}
.scroll-to-top {
  position: fixed;
  bottom: 15px;
  right: 15px;
  opacity: 0;
  transition: all .2s ease-in-out;
}
.show-scroll {
  opacity: 1;
  transition: all .2s ease-in-out;
}

 

The button style creates a round button with an interactive css properties. scroll-to-top class defines the behaviour of the div tag when user scrolls on the results page.

How to use?

Goto Loklak and search a query. On results page, scroll down the window to see upward arrow contained in a red circle like:

On clicking the button, user should be moved to the top of results page.

Resources

Continue Reading

Using CSS Grid in Loklak Search

CSS Grid is the latest web standard for the layouts in the web applications. This is the web standard which allows the HTML page to be viewed as 2-dimensional for laying out the elements in the page. It is thus used in parts of loklak search for layout. In this blog post, I will discuss the basic naming convention for CSS grid and its usage in Loklak Search for layout structuring and responsiveness.

CSS Grid Basics

There are some basic terminologies regarding grid few major ones are the following

Grid Container

The grid container is the container which is the wrapper of all the grid items. It is declared by display: grid, this makes all the direct children of that element to become grid items.

Grid Tracks

We define rows and columns of the grid as the lines, the area between any two lines is called a grid track. Tracks can be defined using any length unit. Grid also introduces an additional length unit to help us create flexible grid tracks. The new fr unit represents a fraction of the available space in the grid container.

Grid Cells

The area between any two horizontal and vertical lines is called a grid cell.

Grid Area

The area formed by the combination of two or more cells is called a grid area.

Using CSS grid in Loklak Search

The CSS grid is used in loklak search uses CSS grid in the feeds page to align elements in a responsive way on mobile and desktop. Earlier there was the issue that on small displays the info box of the results appeared after the feed results, and we needed to make sure that it appears on top on smaller displays. This is the outline of the structure of the feed page.

<div class=”feed-wrapper”>
<div class=”feed-results”>
<!-- Feed Results -->
</div>

<div class=”feed-info-box”>
<!-- Feed Info Box -->
</div>
</div>

Now we use the CSS grid to position the items according to the display width. First we declare the “feed-wrapper” as display:grid to make it a Grid Container, and we associate the rows and columns accordingly.

.feed-wrapper {
   display: grid;
   grid-template-columns: 150px 632px 455px 1fr;
   grid-template-rows: auto;
}

This defines the grid to be consisting of 4 columns of width 150px, 632px,  455px and one remaining unit i.e. 1fr. The rows are set to be auto.

Now we define the grid areas i.e. the names of the areas using the grid-area:<area> css property. This gives names to the elements in the CSS grid.

.feed-results {
   grid-area: feed-results;
}

.feed-info-box {
   grid-area: feed-info-box;
}

The last thing which remains now is to specify the position of these grid elements in the grid cells according to the display width, we use simple media queries along with simple grid area positioning property, i.e. grid-template-areas.

.feed-wrapper {
   /* Other Properties */
   @media(min-width: 1200px) {
      grid-template-areas: ". feed-results feed-info-box .";
   }

   @media(max-width: 1199px) {
      grid-template-columns: 1fr;
      grid-template-areas:
         "feed-info-box"
         "feed-results";
   }
}

This positions both the boxes according to the display width, in one column for large displays, and info box on top of results on mobile displays.

This is how it looks on the large desktop displays

 

This is how it looks on small mobile displays

Links and References

 

 

Continue Reading

Hiding the Scrollbar in HTML in the loklak Media Wall

Loklak media wall needs to provide an appealing view to the user. The issue of visibility of scrollbars appeared on the browsers which uses webkit as a browser engine, for example, Google chrome and some others. This issue caused problems like shifting of elements when scrollbars are visible, bad UI. The task was to hide the scrollbars completely from the application while still making overflow of web page resources available by scrolling.

In this blog, I explain how to hide scrollbars from a webpage and still making scrolling available for the user.

Procedure

 

  • Removing scrollbars from the body division: By default, the <body> tag has the style property overflow:auto which makes overflow available automatically if web page resources exceed the current page dimensions. Therefore, to hide scrollbar from the body, we need to hide the overflow using overflow:hidden.

body {
overflow: hidden;
}

 

  • Creating a child wrapper division for the body: Since body now doesn’t provide scrolling available for the web page, we need to create a wrapper division for the web page for which scrolling would be available, however, scrollbars would not be visible. The idea behind this step is that wrapper division would now act as a wrapper for the web page and if there is some overflow of web page resources, scrolling can be performed from the child division (for which scrollbar can be hidden) instead of parent division.

 

The wrapper division needs to be a block which should occupy total web page available and CSS property overflow should be set to auto.

div.wrapper {
display: block;
width: 100%;
height: 100%;
overflow: auto;
}

 

  • Hiding scrollbars from the wrapper division: The browsers which uses webkit as the browser engines provides scrollbar to every DOM element as webkit-scrollbar which can be customized according to our need. We can now turn scrollbar background to transparent or either set width to 0. Now, since problem of shifting of DOM elements exists, we can need to set width to 0.

.wrapper::-webkitscrollbar {
width: 0px;
}

 

  • Blocking Scroll Blocks: For Angular Material Dialog box, same problem exists since Scroll blocks sets the CSS property of HTML to scroll. This causes the whole  html element to have a scroll. For the same, we can set overflow to hidden by using \deep\ tag to change CSS property deeply of different component of Angular project.

/deep/ html.cdkglobalscrollblock {
overflow: hidden;
}

References

Continue Reading

Creating an Infobox for Mobile View Using Angular in Susper

In Susper, the Information and Analytics boxes disappeared for widths smaller than 1100px, since they were too big to fit in the existing page layout.
In Laptop view:

In Mobile view:

Hence we decided to design a new Info-cum-Analytics box for mobile devices, where the Analytics are displayed only if the ‘Show Analytics’ button is clicked and they are hidden on clicking the ‘Hide Analytics’ button.

The following is the html code for the Infobox:

<div class=“combo-box”>
<appinfobox></app-infobox>
<button class=“btn” id=“toggle-button” (click)=“BoxToggle()” type=“button” datatoggle=“collapse” datatarget=“#statbox” ariaexpanded=“false” ariacontrols=“collapseExample”>
{{boxMessage}} Analytics
</button>
<appstatsbox class=“collapse” id=“statbox”></app-statsbox>
</div>

We can make the following observations:

  • The combo box has both the Info and the Stats box, in addition to a button, which toggles the display status of the Analytics box.
  • To display the appropriate message on the button, we have a special function called BoxToggle() which sets the value of boxMessage()
  • The data-toggle attribute of the button has been set to collapse and the data-target is statbox
  • The statsbox has the class collapse, so that it collapses on clicking on the Toggle button.

The typescript code is as follows:

BoxToggle() {
if (this.boxMessage === ‘Show’) {
this.boxMessage = ‘Hide’;
} else {
this.boxMessage = ‘Show’;
}
}

This code thus effectively toggles between the messages Show and Hide, if the button is clicked when the message says Show, it changes to Hide and vice-versa

The CSS code:

@media screen and (min-width:768px) {
div.combo-box {
display: none;
}
}

The css code ensures that this combo-box is displayed only for widths less than 768px (only mobile and tablet screens).

To view the entire code you can check results.component.html and results.component.css in the Susper repository.

References

  1. W3 Schools for Collapsible buttons and their implementation: https://www.w3schools.com/bootstrap/bootstrap_collapse.asp
  2. Official Bootstrap documentation for collapsible buttons: https://v4-alpha.getbootstrap.com/components/collapse/
Continue Reading

Writing Browser Specific CSS for Susper in Angular

In Susper, we were facing a unique problem for Information box and Analytics box alignment.
At a width of around 1290 px, the boxes fit perfectly in Firefox as shown:

However, they were slipping to the next line in Google Chrome browsers for the same dimension(1290 px)

The solution to this issue was to write browser-specific CSS.
The two most commonly used browser specific tags are

  1. @-moz-document url-prefix() { }: This tag is used to target the Mozilla Firefox browser in particular. Anything written within the curly braces will not apply to any other browser.
  2. @media screen and (-webkit-min-device-pixel-ratio:0) { }: This tag is used to target all browsers that support webkit such as Chrome, Safari etc.

For our problem, we need to use @media screen and (-webkit-min-device-pixel-ratio:0) { }
This was how the code was written for both the components (Information box and Analytics box). Please refer to infobox.component.css and statsbox.component.css for the entire code.

@media screen and (-webkit-min-device-pixel-ratio:0) {
@media screen and (max-width: 1300px) {
.card {
width: 366px;
}
}
}
@media screen and (max-width: 1280px) {
.card {
width: 366px;
}

As a result of this snippet of code, we see the following effects:

  • In Chrome, the boxes change to a smaller width at 1300px itself, thus preventing it from slipping to the next line
  • In Firefox, the boxes change to a smaller width only at 1280px, and not at 1300px, thus achieving the exact design we envisioned.

This is how the display finally looks in Chrome:

References:

  1. Stack overflow on specific CSS tags for Chrome: https://stackoverflow.com/questions/9328832/how-to-apply-specific-css-rules-to-chrome-only
  2. Stack overflow on specific CSS tags for Firefox: https://stackoverflow.com/questions/952861/targeting-only-firefox-with-css
Continue Reading

Making a Sticky Top Navigation bar for Susper using Angular

A lot of websites, require a top navigation bar that sticks to the top, irrespective of the screen dimension size. This blog deals with how the top navigation bar was made sticky in Susper.

  1. Using the correct Bootstrap classes. Notice the code enveloping the navigation bar.

<nav class=“top-nav navbar navbar-static-top navbar-default”>

class=“container-fluid”>

class=“navbar-header” id=“navcontainer”>

</div>
</div>
</nav>

Points to note:

  • Using navbar and navbar-default creates a standard gray navigation bar.
  • Using navbar-static-top makes the navbar stick only to the top of the page and disappear on scrolling down.
  • Using container-fluid creates a container for the contents of the navbar with wide margins
  1.  Now we also need to write some personalized CSS code. Notice the classes navcontainer and  top-nav. This is the CSS code for these classes:

.top-nav{
margin-bottom: 0;
}
#navcontainer {
height: 65px;
width: 100vw;
}#navcontainer ul {
margin: 0;
padding: 0;
list-style-type: none;
}

Points to note:

  • Margin and padding can be set according to how the navbar should look. Click here to know the difference between margins and padding.
  • The height has been customized to 65px in Susper, with a width of 100vw(entire viewpost width).
  1. Lastly, if your navigation bar is inside the body tag, remember that by default, body has a top margin of 57 px. As a result you may see an extra white space on top of your navigation bar. To remove this:
  • Move the navigation bar code out of the body tag. If you can’t then,
  • Place your navigation bar in a container ( resultContainer on the Susper result page) and write this in your CSS file.

.resultContainer{
margin-top: -57px;
}

References:

Continue Reading

Making Customized and Mobile Responsive Drop-down Menus in Susper using Angular

In  Susper, the drop-down menu is customized with colorful search icons and we wanted to maintain the same menu for mobile screens too, however the drop-down menu disappeared for all screens with width less than 767px. This blog can be used to learn how to create css classes for such drop-down menus without using any bootstrap.
This is how the issue was solved.

  1. Replacing standard bootstrap classes : The drop-down menu blocks had a source code as follows:

class=“dropdown-menu”>

class=“row”>

class=“col-sm-4”>

class=“block”>

</div>
</div>

Using col-sm-4 will do the following

  • For widths greater than 767px: Divide each row into four equally sized columns.
  • For widths smaller than 767px: Stack all the columns on top of each other.

Since the drop-down menu’s design was to remain intact, I made the following changes:

  • Replace row with menu-row
  • Replace col-sm-4 with menu-item

Now I wrote personalized css for these classes.

.menu-row{
width: 267px;
gridtemplatecolumns: 1fr 1fr 1fr;
background-color: white;
}
.menu-item{
display: inlineblock;
width: 86px;
}
  • Width: It is used to set the width of the div class, each row now has a width of 267px, with each column in it having a width of 86px.
  • Grid-template-columns: It is used to layout the structure of the template, here 1fr 1fr 1fr represents that there will be three columns in a row.
  • Display: The display is set to inline block to overwrite the default property of the div element to start in a new line.
  1. Custom css for small screens : In standard bootstrap, for screen sizes less than 767px, dropdown class has properties like transparent background, no border etc. that need to be over written. So we add a new id for the div tag as shown:

<div id=“small-drop” class=“dropdown-menu”>

/** Now we add css for it, as shown: **/
@media screen and (max-width: 767px) {
#small-drop{
position: absolute;
background-color: white;
border: 1px solid #cccccc;
right: -38px;
left: auto;
}

  • Position : absolute is used to make sure all our values are absolute and not relative to the higher div hierarchically
  • Border: The values for the border represent the following respectively: Thickness, Style and Color.
  • Auto: Here the value auto for left signifies that there is no fixed value for the left margin, it can take the default value

References:

  1. For working of grids in Bootstrap: https://www.w3schools.com/bootstrap/bootstrap_grid_examples.asp
  2. A useful article for difference between id and class: https://css-tricks.com/the-difference-between-id-and-class

 

Continue Reading

Scaling the logo of the generated events properly in Open Event Webapp

In the Facebook Developer Conference, the logo was too small

27190158-334a5446-5211-11e7-95e8-9690dfe8312e.png

In the Open Tech Summit Event, the logo was too long and increased the height of the navigation bar

77dc9fb0-3966-11e7-92c3-d6321dc98ac7.png

We decide some constraints regarding the width and the height of the logo. We don’t want the width of the logo to exceed greater than 110 pixels in order to not let it become too wide. It would look odd on small and medium screen if barely passable on bigger screens. We also don’t want the logo to become too long so we set a max-height of 45 pixels on the logo. So, we apply a class on the logo element with these properties

.logo-image {
 max-width: 110px;
 max-height: 45px;
}

But simply using these properties doesn’t work properly in some cases as shown in the above screenshots. An alternative approach is to resize the logo appropriately during the generation process itself. There are many different ways in which we can resize the logo. One of them was to scale the logo to a fixed dimension during the generation process. The disadvantage of that approach was that the event logo comes in different size and shapes. So resizing them to a fixed size will change its aspect ratio and it will appear stretched and pixelated. So, that approach is not feasible. We need to think of something different.  After a lot of thinking, we came up with an algorithm for the problem. We know the height of the logo would not be greater than 45px. We calculate the appropriate width and height of the logo, resize the image, and calculate dynamic padding which we add to the anchor element (inside which the image is located) if the height of the image comes out to be less than 45px. This is all done during the generation of the app. Note that the default padding is 5px and we add the extra pixels on top of it. This way, the logo doesn’t appear out of place or pixelated or extra wide and long. The detailed steps are mentioned below

  • Declare variable padding = 5px
  • Get the width, height and aspect ratio of the image.
  • Set the height to 45px and calculate the width according to the aspect ratio. If the width <= 110px, then directly resize the image and no change in padding is necessary
  • If the width > 110px, then make width constant to 110px and calculate height according to the aspect ratio. It will surely come less than 45px. Subtract the difference = (45 – height), divide it by 2 and add it to the padding variable.
  • Apply padding variable on the anchor tag. Now every logo should be displayed nicely and we have fixed the height of the navigation bar = 55px for all cases.

Here is an excerpt of the code. The whole work and discussion can be viewed here

var optimizeLogo = function(image, socket, done) {
 sharp(image).metadata(function(err, metaData) {
   if(err) {
     return done(err);
   }
   var width = metaData.width;
   var height = metaData.height;
   var ratio = width/height;
   var padding = 5;
   var diffHeight = 0;

   height = 45;
   width = Math.floor(45 * ratio);
   if (width > 110) {
     width = 110;
     height = Math.floor(width/ratio);
     diffHeight = 45 - height;
     padding = padding + (diffHeight)/2;
   }
   sharp(image).resize(width, height).toFile(image + '.new', function(err, info) {
     return done(null, padding);
   });
 });
};

It solved the problem. Now the logos of all the events were displaying properly. They were neither too wide, long or short. Here are some screenshots to show the improvements.

Facebook Developer Conference

27262455-d3558540-5474-11e7-852e-ef98888ef647.png

Open Tech Summit 2017

27262033-6f9d2df8-546c-11e7-811b-e35f849072eb.png

Resources:

Continue Reading

Reducing Initial Load Time Of Susper

Susper used to take long time to load the initial page. So, there was a discussion on how to decrease the initial loading time of Susper.

Later on going through issues raised in official Angular repository regarding the time takento load angular applications, we found some of the solutions. Those include:

  • Migrating from development to production during build:
    • This shrinks vendor.js and main.js by minimising them and also removing all packages that are not required on production.
    • Enables inline html and extracting CSS.
    • Disables source maps.
  • Enable Ahead of Time (AoT) compilation.
  • Enable service workers.

After these changes we found the following changes in Susper:

File Name Before (content-length) After
vendor.js 709752 216764
main.js 56412 138361

LOADING TIMES GRAPHS:

After:

Vendor file:

Main.js

Before:

Vendor file:

Main.js

Also we could see that all files are now initiated by service worker:

More about Service Workers could be read at Mozilla and Service Workers in Angular.

Implementation:

While deploying our application, we have added –prod and –aot as extra attributes to ng build .This enables angular to use production mode and ahead of time compilation.

For service workers we have to install @angular/service-worker module. One can install it by using:

npm install @angular/service-worker --save
ng set apps.0.serviceWorker=true

The whole implementation of this is available at this pull:

https://github.com/fossasia/susper.com/pull/597/files

Resources:

 

 

Continue Reading
Close Menu