Sunday 8 March 2015

Web Tutorial: Infinite Scroll, a.k.a The Ngerng Effect

Everyone probably already knows what an Infinite Scroll is. But just in case you've been in a coma the past five years, I'm going to elaborate.

Sometimes, when there's a lot of content to load onto a single page, it makes more sense to only fill up the parts that the user can see, which is the entire width and height of the monitor. Then, when the user scrolls down, more content is loaded. The more the user scrolls, the more content is loaded, until there's no more content left to load. This saves buffer space and loading time.

Facebook are doing it. So are Google Plus, Instagram and Pinterest, among other social media platforms and blogging tools.

So why "The Ngerng Effect"? 

Roy Ngerng is a Singaporean blogger who ran afoul of the law last year, and is currently embroiled in a defamation suit with Prime Minister Lee Hsien Loong.

The entire saga can be found at these links:
http://mothership.sg/2014/05/blogger-roy-ngerng-receives-defamation-suit-from-pm-lee-hsien-loong-2/
https://atans1.wordpress.com/tag/roy-ngerng/
http://alvinology.com/2014/06/05/on-pap-and-defamation-suits/

Putting aside the personal and largely irrelevant question as to whose side I'm on, I'm going to tell you why I call today's web tutorial, which is about the Infinite Scroll, "The Ngerng Effect".

Here goes: Roy Ngerng is a colossal windbag.

Hey, if you don't believe me, just check out his blog at The Heart Truths. This guy goes on practically forever, repeating himself ad nauseam. He rambles on and on about how this defamation suit is a conspiracy and how he aspires to be a voice for the people, and how the government is cheating the people... well, you get the idea.

And in case you still need convincing, here are the links to the blogposts from which I derived the material for today's web tutorial.
http://thehearttruths.com/2015/02/07/pap-continues-to-whitewash-the-truth-about-the-cpf/
http://thehearttruths.com/2015/01/25/singaporeans-i-cannot-be-your-member-of-parliament-in-government/
http://thehearttruths.com/2015/01/17/the-government-has-violated-the-constitution-by-charging-us-for-holding-an-illegal-demonstration-under-the-parks-and-trees-act/

Amusing chap, eh? Wants to represent the people in Parliament, and all that. What a hero. Well, now you can be a hero too, without having to defame the Prime Minister, go through a court case and pay a hefty fine.

Some graphics you may need

Roy's very fond of inserting infographics, so we're going to do the same. Here are some sample ones.

01.png

02.png

03.png

04.png


Let the windbaggery begin! 

Start with the basic HTML code.
<!DOCTYPE html>
<html>
    <head>
        <title>The Ngerng Effect</title>
    </head>

    <body>
        <div id="container">

        </div>
    </body>
</html>

Here we have a div element named container to contain all the bombastic crap text we're going to fill it with. No real styling needed here, so this web tutorial will be sans CSS. The bulk of the magic is in the JavaScript.

Firstly, I've defined a few arrays - prefixes, suffixes, phrases and infographics, and I'm filling it with random repeated text taken from Roy Ngerng's blogposts, like so.

<!DOCTYPE html>
<html>
    <head>
        <title>The Ngerng Effect</title>
        <script>
            var prefixes=[];
            prefixes[0]="";
            prefixes[1]="";
            prefixes[2]="";
            prefixes[3]="";
            prefixes[4]="";
            prefixes[5]="My friends,";
            prefixes[6]="My fellow countrymen,";
            prefixes[7]="My fellow Singaporeans,";
            prefixes[8]="However,";
            prefixes[9]="But still,";

            var suffixes=[];
            suffixes[0]="";
            suffixes[1]="";
            suffixes[2]="";
            suffixes[3]="";
            suffixes[4]="";
            suffixes[5]=" Are you ready?";
            suffixes[6]=" We need more.";
            suffixes[7]=" You have to fight.";
            suffixes[8]=" This is not true.";
            suffixes[9]=" Will you?";

            var phrases=[];
            phrases[0]="You have to fight for yourself.";
            phrases[1]="I am very tired.";
            phrases[2]="Things will only change if you are willing to fight for yourselves.";
            phrases[3]="Singaporeans are still not willing to be ready.";
            phrases[4]="Singaporeans did not stand up, or fight back.";
            phrases[5]="The PAP set us up.";
            phrases[6]="Many Singaporeans have asked me to run for the next general election and become a member of parliament.";
            phrases[7]="I fought because I believed that at some point, Singaporeans would join in, and stand up to fight back.";
            phrases[8]="How many of you are ready for this?";
            phrases[9]="I have lost my job and pretty much my life in Singapore.";
            phrases[10]="The government has made a constitutional breach against our constitutional rights.";
            phrases[11]="We cannot allow the bullying from the prime minister and government to persist.";
            phrases[12]="We cannot allow the abuse of power to continue unchecked.";
            phrases[13]="I did not say anything that is defamatory or against the law.";
            phrases[14]="Surely things can get better.";
            phrases[15]="I still hope that we are ready for change and change will happen.";
            phrases[16]="Because they don't care, and they never cared. ";
            phrases[17]="We've waited too long.";
            phrases[18]="This is it.";
            phrases[19]="Singaporeans are blinded by their fears.";
            phrases[20]="It is up to Singaporeans now.";

            var infographics=[];
            infographics[0]="";
            infographics[1]="";
            infographics[2]="";
            infographics[3]="";
            infographics[4]="";
            infographics[5]="";
            infographics[6]="";
            infographics[7]="";
            infographics[8]="";
            infographics[9]="";
            infographics[10]="";
            infographics[11]="";
            infographics[12]="";
            infographics[13]="";
            infographics[14]="";
            infographics[15]="";
            infographics[16]="00.png";
            infographics[17]="01.png";
            infographics[18]="02.png";
            infographics[19]="03.png";  
         
        </script>
    </head>

    <body>
        <div id="container">

        </div>
    </body>
</html>

You'll notice that some of the array elements are blank. This is deliberate, because I'm going for a random effect. Sometimes, a sentence doesn't have a prefix, suffic or infographic. In the interests of proper programming, I should probably derive an actual formula. But this works just as well in a pinch!

        <script>
            var prefixes=[];
            prefixes[0]="";
            prefixes[1]="";
            prefixes[2]="";
            prefixes[3]="";
            prefixes[4]="";
            prefixes[5]="My friends,";
            prefixes[6]="My fellow countrymen,";
            prefixes[7]="My fellow Singaporeans,";
            prefixes[8]="However,";
            prefixes[9]="But still,";

            var suffixes=[];
            suffixes[0]="";
            suffixes[1]="";
            suffixes[2]="";
            suffixes[3]="";
            suffixes[4]="";
            suffixes[5]=" Are you ready?";
            suffixes[6]=" We need more.";
            suffixes[7]=" You have to fight.";
            suffixes[8]=" This is not true.";
            suffixes[9]=" Will you?";

            var phrases=[];
            phrases[0]="You have to fight for yourself.";
            phrases[1]="I am very tired.";
            phrases[2]="Things will only change if you are willing to fight for yourselves.";
            phrases[3]="Singaporeans are still not willing to be ready.";
            phrases[4]="Singaporeans did not stand up, or fight back.";
            phrases[5]="The PAP set us up.";
            phrases[6]="Many Singaporeans have asked me to run for the next general election and become a member of parliament.";
            phrases[7]="I fought because I believed that at some point, Singaporeans would join in, and stand up to fight back.";
            phrases[8]="How many of you are ready for this?";
            phrases[9]="I have lost my job and pretty much my life in Singapore.";
            phrases[10]="The government has made a constitutional breach against our constitutional rights.";
            phrases[11]="We cannot allow the bullying from the prime minister and government to persist.";
            phrases[12]="We cannot allow the abuse of power to continue unchecked.";
            phrases[13]="I did not say anything that is defamatory or against the law.";
            phrases[14]="Surely things can get better.";
            phrases[15]="I still hope that we are ready for change and change will happen.";
            phrases[16]="Because they don't care, and they never cared. ";
            phrases[17]="We've waited too long.";
            phrases[18]="This is it.";
            phrases[19]="Singaporeans are blinded by their fears.";
            phrases[20]="It is up to Singaporeans now.";

            var infographics=[];
            infographics[0]="";
            infographics[1]="";
            infographics[2]="";
            infographics[3]="";
            infographics[4]="";
            infographics[5]="";
            infographics[6]="";
            infographics[7]="";
            infographics[8]="";
            infographics[9]="";
            infographics[10]="";
            infographics[11]="";
            infographics[12]="";
            infographics[13]="";
            infographics[14]="";
            infographics[15]="";
            infographics[16]="00.png";
            infographics[17]="01.png";
            infographics[18]="02.png";
            infographics[19]="03.png";           

            function createpara()
            {
                var sentences;
                sentences=Math.floor((Math.random() * 3) + 1);

                var para="";

                for (i=1;i<=sentences;i++)
                {
                    para=para+createsentence();
                }

                return para;
            }

            function createsentence()
            {
                var prefix,phrase,suffix,infographic="";
                var sentence="";

                prefix=prefixes[Math.floor(Math.random() * (prefixes.length-1))];
                phrase=phrases[Math.floor(Math.random() * (phrases.length-1))];
                if (prefix!=""){phrase=phrase.substr(0, 1).toLowerCase() + phrase.substr(1)};

                suffix=suffixes[Math.floor(Math.random() * (suffixes.length-1))];
                infographic=infographics[Math.floor(Math.random() * (infographics.length-1))];
  
                sentence=prefix+" "+phrase+suffix+" ";

                if (infographic!=""){sentence=sentence + "<br/><br/><img src=\"" + infographic + "\"> <br/><br/>";}

                return sentence;
            }

        </script>


The createsentence() function joins some of these lines together to form a sentence. More specifically, I am taking a random item from each of these arrays and joining them to form a (somewhat) coherent sentence.

The createpara() function runs the createsentence() function from 1 to 4 times to form a paragraph.

I use the  JavaScript random() function for these, so if you want to read up on it, here's the link (http://www.w3schools.com/jsref/jsref_random.asp).

Now, we're going to define what happens when the user scrolls down. Add the following code.
        <script>
            window.onscroll=scroll;

            var prefixes=[];
            prefixes[0]="";
            prefixes[1]="";
            prefixes[2]="";
            prefixes[3]="";
            prefixes[4]="";
            prefixes[5]="My friends,";
            prefixes[6]="My fellow countrymen,";
            prefixes[7]="My fellow Singaporeans,";
            prefixes[8]="However,";
            prefixes[9]="But still,";

            var suffixes=[];
            suffixes[0]="";
            suffixes[1]="";
            suffixes[2]="";
            suffixes[3]="";
            suffixes[4]="";
            suffixes[5]=" Are you ready?";
            suffixes[6]=" We need more.";
            suffixes[7]=" You have to fight.";
            suffixes[8]=" This is not true.";
            suffixes[9]=" Will you?";

            var phrases=[];
            phrases[0]="You have to fight for yourself.";
            phrases[1]="I am very tired.";
            phrases[2]="Things will only change if you are willing to fight for yourselves.";
            phrases[3]="Singaporeans are still not willing to be ready.";
            phrases[4]="Singaporeans did not stand up, or fight back.";
            phrases[5]="The PAP set us up.";
            phrases[6]="Many Singaporeans have asked me to run for the next general election and become a member of parliament.";
            phrases[7]="I fought because I believed that at some point, Singaporeans would join in, and stand up to fight back.";
            phrases[8]="How many of you are ready for this?";
            phrases[9]="I have lost my job and pretty much my life in Singapore.";
            phrases[10]="The government has made a constitutional breach against our constitutional rights.";
            phrases[11]="We cannot allow the bullying from the prime minister and government to persist.";
            phrases[12]="We cannot allow the abuse of power to continue unchecked.";
            phrases[13]="I did not say anything that is defamatory or against the law.";
            phrases[14]="Surely things can get better.";
            phrases[15]="I still hope that we are ready for change and change will happen.";
            phrases[16]="Because they don't care, and they never cared. ";
            phrases[17]="We've waited too long.";
            phrases[18]="This is it.";
            phrases[19]="Singaporeans are blinded by their fears.";
            phrases[20]="It is up to Singaporeans now.";

            var infographics=[];
            infographics[0]="";
            infographics[1]="";
            infographics[2]="";
            infographics[3]="";
            infographics[4]="";
            infographics[5]="";
            infographics[6]="";
            infographics[7]="";
            infographics[8]="";
            infographics[9]="";
            infographics[10]="";
            infographics[11]="";
            infographics[12]="";
            infographics[13]="";
            infographics[14]="";
            infographics[15]="";
            infographics[16]="00.png";
            infographics[17]="01.png";
            infographics[18]="02.png";
            infographics[19]="03.png";           

            function scroll()
            {

            }


            function createpara()
            {
                var sentences;
                sentences=Math.floor((Math.random() * 3) + 1);

                var para="";

                for (i=1;i<=sentences;i++)
                {
                    para=para+createsentence();
                }

                return para;
            }
            function createsentence()
            {
                var prefix,phrase,suffix,infographic="";
                var sentence="";

                prefix=prefixes[Math.floor(Math.random() * (prefixes.length-1))];
                phrase=phrases[Math.floor(Math.random() * (phrases.length-1))];
                if (prefix!=""){phrase=phrase.substr(0, 1).toLowerCase() + phrase.substr(1)};

                suffix=suffixes[Math.floor(Math.random() * (suffixes.length-1))];
                infographic=infographics[Math.floor(Math.random() * (infographics.length-1))];
  
                sentence=prefix+" "+phrase+suffix+" ";

                if (infographic!=""){sentence=sentence + "<br/><br/><img src=\"" + infographic + "\"> <br/><br/>";}

                return sentence;
            }
        </script>

This is pretty straightforward. When the user scrolls, the scroll() function is triggered. Now the screen height and offset are captured. Here, we create a variable by the name of excess. screen.height is the height of your screen, and window.pageYOffset is the actual number of pixels the user has scrolled down. excess is the remainder.

            function scroll()
            {
                var excess=screen.height^window.pageYOffset;
            }

The scroll() function appends a p delement to the container div. It then fills the p element with the value returned from running the creatapara() function.

 For more about the appendchild() method, follow this link. (http://www.w3schools.com/jsref/met_node_appendchild.asp)

Now for the logic!


            function scroll()
            {
                var excess=screen.height^window.pageYOffset;
                var moretext;

                if (excess>(0.5*screen.height)&&screen.height<window.pageYOffset)
                {           
                    moretext= document.createElement("p");                
                    document.getElementById("container").appendChild(moretext);
                    moretext.innerHTML=createpara();
                }

            }

Here, we see that if the excess exceeds the screen size by more than 50%, the createpara() function kicks in, thereby diminishing the ratio of the offset to the screen size till it's less than 50% again. And this goes on forever. Just like Roy Ngerng. What a guy!

Add this to your HTML
    <body>
        <div id="container">

        </div>

        <script>
            var starttext;

            for (j=1;j<=50;j++)
            {
                    starttext= document.createElement("p");               
                    document.getElementById("container").appendChild(starttext);
                    starttext.innerHTML=createpara();
            }
        </script>

    </body>

This basically runs the createpara() function 50 times at the start, just to fill up your page. I should probably do some calculation to calibrate the number of times to the screen's height, but that's too much like work.

So run the code... 

Do you see that when you scroll down, more and more text is added to the bottom of the screen? That's the Infinite Scroll at work.

But some of these sentences don't really make sense! 

That's OK. Neither does Roy.

Just to be clear, this is not a critique of Roy Ngerng's character or the cause he claims to be fighting for. It's a critique of his writing style, which irritates the bejeezus out of me. The programmer's adage: Minimum input, maximum output. Ngerng has somehow managed to do it in reverse.

Yours infinitely,
T___T

No comments:

Post a Comment