Tuesday, January 7, 2020

Implement TabPages in Vanilla JS and CSS

Today, as the lunch break challenge I decided to create Tabs in Vanilla JS and that's what I made:

About
Details
Contacts

In descriptive writing, the author does not just tell the reader what was seen, felt, tested, smelled, or heard. Rather, the author describes something from their own experience and, through careful choice of words and phrasing, makes it seem real. Descriptive writing is vivid, colorful, and detailed.

Good descriptive writing creates an impression in the reader's mind of an event, a place, a person, or a thing. The writing will be such that it will set a mood or describe something in such detail that if the reader saw it, they would recognize it.

To be concrete, descriptive writing has to offer specifics the reader can envision. Rather than "Her eyes were the color of blue rocks" (Light blue? Dark blue? Marble? Slate?), try instead, "Her eyes sparkled like sapphires in the dark."


The HTML is the following:

<html>
<head>
    
    
    Tabs Example
    
</head>

<body>
    

About

In descriptive writing, the author does not just tell the reader what was seen, felt, tested, smelled, or heard. Rather, the author describes something from their own experience and, through careful choice of words and phrasing, makes it seem real. Descriptive writing is vivid, colorful, and detailed.

Good descriptive writing creates an impression in the reader's mind of an event, a place, a person, or a thing. The writing will be such that it will set a mood or describe something in such detail that if the reader saw it, they would recognize it.

To be concrete, descriptive writing has to offer specifics the reader can envision. Rather than "Her eyes were the color of blue rocks" (Light blue? Dark blue? Marble? Slate?), try instead, "Her eyes sparkled like sapphires in the dark."

Details

To be evocative, descriptive writing has to unite the concrete image with phrasing that evokes the impression the writer wants the reader to have. Consider "her eyes shone like sapphires, warming my night" versus "the woman's eyes had a light like sapphires, bright and hard." Each phrase uses the same concrete image, then employs evocative language to create different impressions.

To be plausible, the descriptive writer has to constrain the concrete, evocative image to suit the reader's knowledge and attention span. "Her eyes were brighter than the sapphires in the armrests of the Tipu Sultan's golden throne, yet sharper than the tulwars of his cruelest executioners" will have the reader checking their phone halfway through. "Her eyes were sapphires, bright and hard" creates the same effect in a fraction of the reading time. As always in the craft of writing: when in doubt, write less.

n this excerpt from Jamaica Inn by Daphne du Maurier, notice the writer's choice of adjectives, adverbs, and verbs. Granite. Mizzling. Du Maurier's choice of words allows the reader to almost feel the weather occurring on the page.

Contacts

First name:

Last name:

A paragraph without a header.

</body> </html>
  1. <html>
  2. <head>
  3. <script src="./main.js"></script>
  4. <link rel="stylesheet" href="main.css">
  5. <title>Tabs Example</title>
  6. <script>
  7. document.addEventListener('DOMContentLoaded', function () {
  8. tab('mainTab');
  9. });
  10. </script>
  11. </head>
  12. <body>
  13. <div id="mainTab">
  14. <div class="tabPage">
  15. <h1 class="tabHeader">About</h1>
  16. <div class="tabPageContent">
  17. <p>In descriptive writing, the author does not just tell the reader what was seen, felt, tested,
  18. smelled, or
  19. heard. Rather, the author describes something from their own experience and, through careful choice
  20. of
  21. words and phrasing, makes it seem real. Descriptive writing is vivid, colorful, and detailed.</p>
  22. <p>Good descriptive writing creates an impression in the reader's mind of an event, a place, a person,
  23. or a
  24. thing. The writing will be such that it will set a mood or describe something in such detail that if
  25. the
  26. reader saw it, they would recognize it.</p>
  27. <p>To be concrete, descriptive writing has to offer specifics the reader can envision. Rather than "Her
  28. eyes
  29. were the color of blue rocks" (Light blue? Dark blue? Marble? Slate?), try instead, "Her eyes
  30. sparkled
  31. like sapphires in the dark."</p>
  32. </div>
  33. </div>
  34. <div class="tabPage">
  35. <h1 class="tabHeader">Details</h1>
  36. <div class="tabPageContent">
  37. <p>To be evocative, descriptive writing has to unite the concrete image with phrasing that evokes the
  38. impression the writer wants the reader to have. Consider "her eyes shone like sapphires, warming my
  39. night" versus "the woman's eyes had a light like sapphires, bright and hard." Each phrase uses the
  40. same
  41. concrete image, then employs evocative language to create different impressions.</p>
  42. <p>To be plausible, the descriptive writer has to constrain the concrete, evocative image to suit the
  43. reader's knowledge and attention span. "Her eyes were brighter than the sapphires in the armrests of
  44. the
  45. Tipu Sultan's golden throne, yet sharper than the tulwars of his cruelest executioners" will have
  46. the
  47. reader checking their phone halfway through. "Her eyes were sapphires, bright and hard" creates the
  48. same
  49. effect in a fraction of the reading time. As always in the craft of writing: when in doubt, write
  50. less.
  51. </p>
  52. <p>n this excerpt from Jamaica Inn by Daphne du Maurier, notice the writer's choice of adjectives,
  53. adverbs,
  54. and verbs. Granite. Mizzling. Du Maurier's choice of words allows the reader to almost feel the
  55. weather
  56. occurring on the page.</p>
  57. </div>
  58. </div>
  59. <div class="tabPage">
  60. <h1 class="tabHeader">Contacts</h1>
  61. <div class="tabPageContent">
  62. <form>
  63. First name:<br>
  64. <input type="text" name="firstname"><br>
  65. Last name:<br>
  66. <input type="text" name="lastname">
  67. </form>
  68. </div>
  69. </div>
  70. <div class="tabPage">
  71. <div class="tabPageContent">
  72. <p>A paragraph without a header.</p>
  73. </div>
  74. </div>
  75. </div>
  76. </body>
  77. </html>
<html>
<head>
    <script src="./main.js"></script>
    <link rel="stylesheet" href="main.css">
    <title>Tabs Example</title>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            tab('mainTab');
        });
    </script>
</head>

<body>
    <div id="mainTab">

        <div class="tabPage">
            <h1 class="tabHeader">About</h1>
            <div class="tabPageContent">
                <p>In descriptive writing, the author does not just tell the reader what was seen, felt, tested,
                    smelled, or
                    heard. Rather, the author describes something from their own experience and, through careful choice
                    of
                    words and phrasing, makes it seem real. Descriptive writing is vivid, colorful, and detailed.</p>
                <p>Good descriptive writing creates an impression in the reader's mind of an event, a place, a person,
                    or a
                    thing. The writing will be such that it will set a mood or describe something in such detail that if
                    the
                    reader saw it, they would recognize it.</p>
                <p>To be concrete, descriptive writing has to offer specifics the reader can envision. Rather than "Her
                    eyes
                    were the color of blue rocks" (Light blue? Dark blue? Marble? Slate?), try instead, "Her eyes
                    sparkled
                    like sapphires in the dark."</p>
            </div>
        </div>

        <div class="tabPage">
            <h1 class="tabHeader">Details</h1>
            <div class="tabPageContent">
                <p>To be evocative, descriptive writing has to unite the concrete image with phrasing that evokes the
                    impression the writer wants the reader to have. Consider "her eyes shone like sapphires, warming my
                    night" versus "the woman's eyes had a light like sapphires, bright and hard." Each phrase uses the
                    same
                    concrete image, then employs evocative language to create different impressions.</p>
                <p>To be plausible, the descriptive writer has to constrain the concrete, evocative image to suit the
                    reader's knowledge and attention span. "Her eyes were brighter than the sapphires in the armrests of
                    the
                    Tipu Sultan's golden throne, yet sharper than the tulwars of his cruelest executioners" will have
                    the
                    reader checking their phone halfway through. "Her eyes were sapphires, bright and hard" creates the
                    same
                    effect in a fraction of the reading time. As always in the craft of writing: when in doubt, write
                    less.
                </p>
                <p>n this excerpt from Jamaica Inn by Daphne du Maurier, notice the writer's choice of adjectives,
                    adverbs,
                    and verbs. Granite. Mizzling. Du Maurier's choice of words allows the reader to almost feel the
                    weather
                    occurring on the page.</p>
            </div>
        </div>

        <div class="tabPage">
            <h1 class="tabHeader">Contacts</h1>
            <div class="tabPageContent">
                <form>
                    First name:<br>
                    <input type="text" name="firstname"><br>
                    Last name:<br>
                    <input type="text" name="lastname">
                </form>
            </div>
        </div>

        <div class="tabPage">
            <div class="tabPageContent">
                <p>A paragraph without a header.</p>
            </div>
        </div>
    </div>
</body>

</html>

If we comment out the tab('mainTab'); function on the line #8, the magic disappears:

About

In descriptive writing, the author does not just tell the reader what was seen, felt, tested, smelled, or heard. Rather, the author describes something from their own experience and, through careful choice of words and phrasing, makes it seem real. Descriptive writing is vivid, colorful, and detailed.

Good descriptive writing creates an impression in the reader's mind of an event, a place, a person, or a thing. The writing will be such that it will set a mood or describe something in such detail that if the reader saw it, they would recognize it.

To be concrete, descriptive writing has to offer specifics the reader can envision. Rather than "Her eyes were the color of blue rocks" (Light blue? Dark blue? Marble? Slate?), try instead, "Her eyes sparkled like sapphires in the dark."

Details

To be evocative, descriptive writing has to unite the concrete image with phrasing that evokes the impression the writer wants the reader to have. Consider "her eyes shone like sapphires, warming my night" versus "the woman's eyes had a light like sapphires, bright and hard." Each phrase uses the same concrete image, then employs evocative language to create different impressions.

To be plausible, the descriptive writer has to constrain the concrete, evocative image to suit the reader's knowledge and attention span. "Her eyes were brighter than the sapphires in the armrests of the Tipu Sultan's golden throne, yet sharper than the tulwars of his cruelest executioners" will have the reader checking their phone halfway through. "Her eyes were sapphires, bright and hard" creates the same effect in a fraction of the reading time. As always in the craft of writing: when in doubt, write less.

n this excerpt from Jamaica Inn by Daphne du Maurier, notice the writer's choice of adjectives, adverbs, and verbs. Granite. Mizzling. Du Maurier's choice of words allows the reader to almost feel the weather occurring on the page.

Contacts

First name:

Last name:

A paragraph without a header.


JavaScript that builds tab pages:

const _tabHeaders = [];
const _tabPages = [];
let _pageContainer;


function tab(elementId) {
    console.log('Trying to tabify the element ' + elementId);

    const root = document.getElementById(elementId);
    if (!root) {
        console.error('Cannot find an element with ID=' + elementId);
        return;
    }

    const tabPages = root.getElementsByClassName('tabPage');
    console.log(tabPages.length + ' tab pages found');

    //Extract tab headers and tab content
    Array.from(tabPages).forEach((tabPage, index) => extractTabPage(tabPage, index));

    //Clear root content
    root.innerHTML = "";

    //Build new content
    buildTabButtons(root);

    //Build page container
    buildPageContainer(root);

    //Select the first tab
    clickTab(0);
}


function extractTabPage(tabPage, index) {
    if (!tabPage) {
        console.error('Cannot add NULL tab page');
        return;
    }

    const pageHeader = tabPage.getElementsByClassName('tabHeader')[0];
    if (!pageHeader) {
        console.warn("Cannot add a tab page without a header. No header - no page. That's it.")
        return;
    }

    const pageContent = tabPage.getElementsByClassName('tabPageContent')[0];
    if (!pageContent) {
        console.warn("Cannot add a tab page without a content. No content - no page. Pretty obvious, isn't it?")
        return;
    }

    console.log('Adding new page ' + pageHeader.innerText);
    _tabHeaders.push(createHeaderButton(pageHeader.innerText, index));
    _tabPages.push(pageContent.innerHTML);
}


function createHeaderButton(headerText, index) {
    let headerButton = document.createElement('div');
    headerButton.innerText = headerText;
    headerButton.setAttribute('class', 'headerButton');
    headerButton.setAttribute('onclick', `clickTab(${index})`);
    return headerButton;
}


function buildTabButtons(root) {
    //Create the tab buttons container
    let buttonsContainer = document.createElement('div');
    buttonsContainer.setAttribute('class', 'buttonsContainer');
    root.appendChild(buttonsContainer);

    //Create a button for every header
    _tabHeaders.forEach(header => buttonsContainer.appendChild(header));
}

function buildPageContainer(root) {
    //Create the page container
    _pageContainer = document.createElement('div');
    _pageContainer.setAttribute('class', 'pageContainer');
    root.appendChild(_pageContainer);
}

function clickTab(index) {
    _tabHeaders.forEach(header => header.setAttribute('class', 'headerButton'));
    _tabHeaders[index].setAttribute('class', 'headerButton active');
    _pageContainer.innerHTML = _tabPages[index];
}
  1. const _tabHeaders = [];
  2. const _tabPages = [];
  3. let _pageContainer;
  4. function tab(elementId) {
  5. console.log('Trying to tabify the element ' + elementId);
  6. const root = document.getElementById(elementId);
  7. if (!root) {
  8. console.error('Cannot find an element with ID=' + elementId);
  9. return;
  10. }
  11. const tabPages = root.getElementsByClassName('tabPage');
  12. console.log(tabPages.length + ' tab pages found');
  13. //Extract tab headers and tab content
  14. Array.from(tabPages).forEach((tabPage, index) => extractTabPage(tabPage, index));
  15. //Clear root content
  16. root.innerHTML = "";
  17. //Build new content
  18. buildTabButtons(root);
  19. //Build page container
  20. buildPageContainer(root);
  21. //Select the first tab
  22. clickTab(0);
  23. }
  24. function extractTabPage(tabPage, index) {
  25. if (!tabPage) {
  26. console.error('Cannot add NULL tab page');
  27. return;
  28. }
  29. const pageHeader = tabPage.getElementsByClassName('tabHeader')[0];
  30. if (!pageHeader) {
  31. console.warn("Cannot add a tab page without a header. No header - no page. That's it.")
  32. return;
  33. }
  34. const pageContent = tabPage.getElementsByClassName('tabPageContent')[0];
  35. if (!pageContent) {
  36. console.warn("Cannot add a tab page without a content. No content - no page. Pretty obvious, isn't it?")
  37. return;
  38. }
  39. console.log('Adding new page ' + pageHeader.innerText);
  40. _tabHeaders.push(createHeaderButton(pageHeader.innerText, index));
  41. _tabPages.push(pageContent.innerHTML);
  42. }
  43. function createHeaderButton(headerText, index) {
  44. let headerButton = document.createElement('div');
  45. headerButton.innerText = headerText;
  46. headerButton.setAttribute('class', 'headerButton');
  47. headerButton.setAttribute('onclick', `clickTab(${index})`);
  48. return headerButton;
  49. }
  50. function buildTabButtons(root) {
  51. //Create the tab buttons container
  52. let buttonsContainer = document.createElement('div');
  53. buttonsContainer.setAttribute('class', 'buttonsContainer');
  54. root.appendChild(buttonsContainer);
  55. //Create a button for every header
  56. _tabHeaders.forEach(header => buttonsContainer.appendChild(header));
  57. }
  58. function buildPageContainer(root) {
  59. //Create the page container
  60. _pageContainer = document.createElement('div');
  61. _pageContainer.setAttribute('class', 'pageContainer');
  62. root.appendChild(_pageContainer);
  63. }
  64. function clickTab(index) {
  65. _tabHeaders.forEach(header => header.setAttribute('class', 'headerButton'));
  66. _tabHeaders[index].setAttribute('class', 'headerButton active');
  67. _pageContainer.innerHTML = _tabPages[index];
  68. }
const _tabHeaders = [];
const _tabPages = [];
let _pageContainer;


function tab(elementId) {
    console.log('Trying to tabify the element ' + elementId);

    const root = document.getElementById(elementId);
    if (!root) {
        console.error('Cannot find an element with ID=' + elementId);
        return;
    }

    const tabPages = root.getElementsByClassName('tabPage');
    console.log(tabPages.length + ' tab pages found');

    //Extract tab headers and tab content
    Array.from(tabPages).forEach((tabPage, index) => extractTabPage(tabPage, index));

    //Clear root content
    root.innerHTML = "";

    //Build new content
    buildTabButtons(root);

    //Build page container
    buildPageContainer(root);

    //Select the first tab
    clickTab(0);
}


function extractTabPage(tabPage, index) {
    if (!tabPage) {
        console.error('Cannot add NULL tab page');
        return;
    }

    const pageHeader = tabPage.getElementsByClassName('tabHeader')[0];
    if (!pageHeader) {
        console.warn("Cannot add a tab page without a header. No header - no page. That's it.")
        return;
    }

    const pageContent = tabPage.getElementsByClassName('tabPageContent')[0];
    if (!pageContent) {
        console.warn("Cannot add a tab page without a content. No content - no page. Pretty obvious, isn't it?")
        return;
    }

    console.log('Adding new page ' + pageHeader.innerText);
    _tabHeaders.push(createHeaderButton(pageHeader.innerText, index));
    _tabPages.push(pageContent.innerHTML);
}


function createHeaderButton(headerText, index) {
    let headerButton = document.createElement('div');
    headerButton.innerText = headerText;
    headerButton.setAttribute('class', 'headerButton');
    headerButton.setAttribute('onclick', `clickTab(${index})`);
    return headerButton;
}


function buildTabButtons(root) {
    //Create the tab buttons container
    let buttonsContainer = document.createElement('div');
    buttonsContainer.setAttribute('class', 'buttonsContainer');
    root.appendChild(buttonsContainer);

    //Create a button for every header
    _tabHeaders.forEach(header => buttonsContainer.appendChild(header));
}

function buildPageContainer(root) {
    //Create the page container
    _pageContainer = document.createElement('div');
    _pageContainer.setAttribute('class', 'pageContainer');
    root.appendChild(_pageContainer);
}

function clickTab(index) {
    _tabHeaders.forEach(header => header.setAttribute('class', 'headerButton'));
    _tabHeaders[index].setAttribute('class', 'headerButton active');
    _pageContainer.innerHTML = _tabPages[index];
}

CSS:

.buttonsContainer {
  margin-left: 5px;
}

.pageContainer {
  border: 1px gray solid;
  box-shadow: gray 3px 3px;
  padding: 10px;
}

.headerButton {
  display: inline-block;
  font-size: 20px;
  background-color: #e1c340;
  padding: 2px 10px;
  border: 1px gray solid;
  border-top-left-radius: 7px 20px;
  border-top-right-radius: 7px 20px;
  margin-left: -5px;
  position: relative;
  cursor: pointer;
}

.active {
  z-index: 10;
  background-color: #f8ea8c;
  padding: 2px 15px;
}
  1. .buttonsContainer {
  2. margin-left: 5px;
  3. }
  4. .pageContainer {
  5. border: 1px gray solid;
  6. box-shadow: gray 3px 3px;
  7. padding: 10px;
  8. }
  9. .headerButton {
  10. display: inline-block;
  11. font-size: 20px;
  12. background-color: #e1c340;
  13. padding: 2px 10px;
  14. border: 1px gray solid;
  15. border-top-left-radius: 7px 20px;
  16. border-top-right-radius: 7px 20px;
  17. margin-left: -5px;
  18. position: relative;
  19. cursor: pointer;
  20. }
  21. .active {
  22. z-index: 10;
  23. background-color: #f8ea8c;
  24. padding: 2px 15px;
  25. }
.buttonsContainer {
  margin-left: 5px;
}

.pageContainer {
  border: 1px gray solid;
  box-shadow: gray 3px 3px;
  padding: 10px;
}

.headerButton {
  display: inline-block;
  font-size: 20px;
  background-color: #e1c340;
  padding: 2px 10px;
  border: 1px gray solid;
  border-top-left-radius: 7px 20px;
  border-top-right-radius: 7px 20px;
  margin-left: -5px;
  position: relative;
  cursor: pointer;
}

.active {
  z-index: 10;
  background-color: #f8ea8c;
  padding: 2px 15px;
}

Also, I wanted to implement the mouseover effect, but the lunch break was over..

You can try it on JSFiddle: https://jsfiddle.net/AndrewBuntsev/ef6at3L5/

No comments:

Post a Comment