Showing posts with label Semantic UI. Show all posts
Showing posts with label Semantic UI. Show all posts

Monday, 12 July 2021

Web Tutorial: The JS Datepicker (Part 1/4)

Date inputs on the web are important where data entry is concerned. Not only does proper date formatting need to be observed, the user interface needs to be as idiot-proof as possible. These days, it's all easily doable via an increasingly wide array of datepickers that are available in libraries like Semantic UI and jQueryUI.

However, back in my day, this was a whole other proposition altogether. In fact, I first implemented a JavaScript datepicker by copying calendar widget code from some Indian blog, an act which caused the level of my JavaScript to soar once I understood how it was done. And today, I will be taking you through the same process.

It all begins with some HTML, and a simple span element for which we will provide an id of cal1. This will remain invisible for now, since we haven't placed any content within it.
<!DOCTYPE html>
<html>
    <head>
        <title>Calendar</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>
        <span id="cal1"></span>
    </body>
</html>


But this is where it escalates, because beyond that bit of HTML, we go right into the JavaScript. For this, we will need a JavaScript object. It will be called calendar. The first property, container, is set to null. This will later on hold the object cal1.
<script>
    var calendar =
    {
        container: null,
    }

</script>


Next is selectedDate. This will be the date that defines what values your datepicker is going to display.
<script>
    var calendar =
    {
        container: null,
        selectedDate: null,
    }
</script>


textbox is what the user will see initially. hiddenTextbox will hold the actual value that your widget will send to the server. btnDisplay, when clicked, shows or hides all other controls.
<script>
    var calendar =
    {
        container: null,
        selectedDate: null,
        textbox: undefined,
        hiddenTextbox: undefined,
        btnDisplay: undefined,

    }
</script>


monthPicker is the drop-down list we will create later, to hold all the months. datePickers is an array of all the current days in the selected month. daysContainer is the div that will hold the display of all the days.
<script>
    var calendar =
    {
        container: null,
        selectedDate: null,
        textbox: undefined,
        hiddenTextbox: undefined,
        btnDisplay: undefined,
        monthPicker: undefined,
        datePickers: undefined,
        daysContainer: undefined,

    }
</script>


days and months are arrays we can populate right away - with all possible values of weekdays and month names respectively.
<script>
    var calendar =
    {
        container: null,
        selectedDate: null,
        textbox: undefined,
        hiddenTextbox: undefined,
        btnDisplay: undefined,
        monthPicker: undefined,
        datePickers: undefined,
        daysContainer: undefined,
        days: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
        months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],

    }
</script>


Next, we have initialize() as a method. This is the method that transforms the span element into a badass datepicker! It will accept a string as a parameter. This will be the id of the span element we want to change into a datepicker.
var calendar =
{
    container: null,
    selectedDate: null,
    textbox: undefined,
    hiddenTextbox: undefined,
    btnDisplay: undefined,
    monthPicker: undefined,
    datePickers: undefined,
    daysContainer: undefined,
    days: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
    months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
    initialize: function(id)
    {

    },

}


Before we go further, we should add a script tag at the end of the body tag. In it, call initialize() and pass in "cal1" as an argument. So this will transform cal1.
<body>
    <span id="cal1"></span>

    <script>
        calendar.initialize("cal1");
    </script>

</body>


In here, set selectedDate to today's date.
initialize: function(id)
{
    this.selectedDate = new Date();
},


Then set container to the object pointed to by id.
initialize: function(id)
{
    this.selectedDate = new Date();
    this.container = document.getElementById(id);
},


Add the CSS classes calenderContainer and hide to container.
initialize: function(id)
{
    this.selectedDate = new Date();
    this.container = document.getElementById(id);
    this.container.classList.add("calendarContainer");
    this.container.classList.add("hide");

},


And now, let's add the CSS class calendarContainer. Here, we set the display property to inline-block so that we can set width and height. Then we add font properties. And a blue outline, just for visibility.
<style>
    .calendarContainer
    {
        width: 350px;
        height: 30px;
        font-size: 12px;
        font-family: arial;
        display: inline-block;
        outline: 1px solid blue;
    }

</style>


Here, you see the blue outline denoting your span element.


Then we add the CSS class hide. For this, the overflow property is set to hidden. This will not hide your date field, but it will hide all the other controls in the datepicker.
<style>
    .calendarContainer
    {
        width: 350px;
        height: 30px;
        font-size: 12px;
        font-family: arial;
        display: inline-block;
        outline: 1px solid blue;
    }

    .hide
    {
        overflow: hidden;
    }

</style>


Back to the initialize() method. Use the createElement() method of the document object to create two divs, top and bottom. Add CSS classes top and bottom respectively.
initialize: function(id)
{
    this.selectedDate = new Date();
    this.container = document.getElementById(id);
    this.container.classList.add("calendarContainer");
    this.container.classList.add("hide");

    var top = document.createElement("div");
    top.classList.add("top");

    var bottom = document.createElement("div");
    bottom.classList.add("bottom");

},


Then append top and bottom to container.
var top = document.createElement("div");
top.classList.add("top");

var bottom = document.createElement("div");
bottom.classList.add("bottom");

this.container.appendChild(top);
this.container.appendChild(bottom);


You still won't see anything yet. We will need to add the CSS classes. Here, you'll see that widths and heights have been defined for top and bottom. For bottom, I've even made the background color grey and added round corners.
<style>
    .calendarContainer
    {
        width: 350px;
        height: 30px;
        font-size: 12px;
        font-family: arial;
        display: inline-block;
        outline: 1px solid blue;
    }

    .hide
    {
        overflow: hidden;
    }

    .calendarContainer .top
    {
        width: 100%;
        height: 30px;
    }


    .calendarContainer .bottom
    {
        width: 100%;
        height: 200px;
        border: 1px solid rgba(200, 200, 200, 1);
        border-radius: 5px;
        padding: 2px 0 2px 0;
        background-color: rgba(250, 250, 250, 1);
    }

</style>


Let's temporarily disable this line so we can see what's been added.
initialize: function(id)
{
    this.selectedDate = new Date();
    this.container = document.getElementById(id);
    this.container.classList.add("calendarContainer");
    //this.container.classList.add("hide");

    var top = document.createElement("div");
    top.classList.add("top");

    var bottom = document.createElement("div");
    bottom.classList.add("bottom");
},


Here, you'll see that bottom is the conspicuous grey box. Where's top, then? Well, top is currently occupying that space within the blue box. Remember that the overflow property is no longer set to hidden (due to us commenting away the line that adds the hide CSS class); so now that container contains both top and bottom, since they both have 100% width, bottom naturally goes below top.


Next, we create an input element, give it an id based on "cal1", and then append it to top. It will be read-only, because it's meant to look like a text input, but without actually functioning like one.
this.container.appendChild(top);
this.container.appendChild(bottom);

var textbox = document.createElement("input");
textbox.type = "text";
textbox.readOnly = true;
textbox.id = "txt_" + id;
top.appendChild(textbox);


There, this is the textbox we just added.


Here, we do something similar with a newly-created div element, btnDisplay. This is supposed to be the button that hides and displays your controls.
var textbox = document.createElement("input");
textbox.type = "text";
textbox.readOnly = true;
textbox.id = "txt_" + id;
top.appendChild(textbox);

var btnDisplay = document.createElement("div");
btnDisplay.classList.add("button");
btnDisplay.classList.add("spaceleft");
btnDisplay.id = "btndisplay_" + id;
btnDisplay.innerHTML = "&#9660;";
top.appendChild(btnDisplay);


Here, you can see the tiny down arrow icon we just added. This all needs styling, and that's what we will do next. Note that the CSS class for this is button, and one called spaceleft.


Here, we style the textbox, giving it a width and height and rounded corners. More importantly, display is set to inline-block so it functions as a block element, and in turn allows us to use the float property.
.calendarContainer .bottom
{
    width: 100%;
    height: 200px;
    border: 1px solid rgba(200, 200, 200, 1);
    border-radius: 5px;
    padding: 2px 0 2px 0;
    background-color: rgba(250, 250, 250, 1);
}

.calendarContainer input[type=text]
{
    width: 310px;
    height: 20px;
    border-radius: 5px;
    display: inline-block;
    float: left;
}


There, now that we styled the textbox, it's longer and fancier. And the float property ensures that the div element btnDisplay now lines up nicely next to it instead of under it.


Now, here's some styling for the CSS class button. This is a generic class for all the buttons we will be incorporating into the widget. I've made them square with rounded corners, a grey border and an even lighter grey background, with the background darkening upon a mouseover. Get creative!
.calendarContainer input[type=text]
{
    width: 310px;
    height: 20px;
    border-radius: 5px;
    display: inline-block;
    float: left;
}

.calendarContainer .button
{
    width: 23px;
    height: 23px;
    border: 1px solid rgba(200, 200, 200, 1);
    border-radius: 5px;
    text-align: center;
    cursor: pointer;
    float: left;
    background-color: rgba(255, 255, 255, 1);
    color: rgba(0, 0, 0, 1);
    font-size: 14px;
}

.calendarContainer .button:hover
{
    background-color: rgba(200, 200, 200, 1);
}


There's your nicely styled button.


Now we define the spaceleft CSS class. It basically sets the margin-left property so that there's a bit of space to the left. Nothing much to it!
.calendarContainer .button:hover
{
    background-color: rgba(200, 200, 200, 1);
}

.spaceleft
{
    margin-left: 2px;
}


There you can see that tiny space.


All right, time for the next bit!

We need to place more controls in there. Here, we do what we did for btnDisplay, except we append it to bottom. This one is btnMonthDec, and it will be used to decrement months. For the icon, we use ◀.
var btnDisplay = document.createElement("div");
btnDisplay.classList.add("button");
btnDisplay.classList.add("spaceleft");
btnDisplay.id = "btndisplay_" + id;
btnDisplay.innerHTML = "&#9660;";
top.appendChild(btnDisplay);

var btnMonthDec = document.createElement("div");
btnMonthDec.classList.add("button");
btnMonthDec.classList.add("spaceleft");
btnMonthDec.innerHTML = "&#9664;";
bottom.appendChild(btnMonthDec);


Now you see, we've already created the styling. So it renders nicely.


Next up is the month selector. For this, we create a select element, and style it using spaceleft. As with all the other elements so far, we give it an id based on "cal1".
var btnMonthDec = document.createElement("div");
btnMonthDec.classList.add("button");
btnMonthDec.classList.add("spaceleft");
btnMonthDec.innerHTML = "&#9664;";
bottom.appendChild(btnMonthDec);

var monthPicker = document.createElement("select");
monthPicker.classList.add("spaceleft");
monthPicker.id = "monthpicker_" + id;


Remember the months array? Now we get to use it. Iterate through it and create a series of option elements that will be placed within monthPicker.
var monthPicker = document.createElement("select");
monthPicker.classList.add("spaceleft");
monthPicker.id = "monthpicker_" + id;

for (var i = 0; i < this.months.length; i++)
{
    var option = document.createElement("option");
    option.value = i + 1;
    option.innerHTML = this.months[i];
    monthPicker.appendChild(option);
}


And then append monthPicker to bottom.
var monthPicker = document.createElement("select");
monthPicker.classList.add("spaceleft");
monthPicker.id = "monthpicker_" + id;

for (var i = 0; i < this.months.length; i++)
{
    var option = document.createElement("option");
    option.value = i + 1;
    option.innerHTML = this.months[i];
    monthPicker.appendChild(option);
}

bottom.appendChild(monthPicker);


And here's the drop-down list of months.


Pause a moment here to style this. We will adjust the width, height and font size, and give rounded corners. display will be set to inline-block and float to left.
.calendarContainer .button:hover
{
    background-color: rgba(200, 200, 200, 1);
}

.calendarContainer select
{
    width: 100px;
    height: 24px;
    border-radius: 5px;
    display: inline-block;
    float: left;
    font-size: 1.6em;
}


.spaceleft
{
    margin-left: 2px;
}


Looking nicer now!


Now it's time for btnMonthInc, the element that does the opposite of btnMonthDec. It will use ▶ as an icon.
bottom.appendChild(monthPicker);

var btnMonthInc = document.createElement("div");
btnMonthInc.classList.add("button");
btnMonthInc.classList.add("spaceleft");
btnMonthInc.innerHTML = "&#9654;";
bottom.appendChild(btnMonthInc);


Taking shape here...


Next, we do another series of buttons. This time, it's for the year. This one is btnYearDecTen. This decrements the year by 10. Notice that, this time, we style it using spaceleft_large. We'll use the empty triangle left pointer ◁.
var btnMonthInc = document.createElement("div");
btnMonthInc.classList.add("button");
btnMonthInc.classList.add("spaceleft");
btnMonthInc.innerHTML = "&#9654;";
bottom.appendChild(btnMonthInc);

var btnYearDecTen = document.createElement("div");
btnYearDecTen.classList.add("button");
btnYearDecTen.classList.add("spaceleft_large");
btnYearDecTen.innerHTML = "&#9665;";
bottom.appendChild(btnYearDecTen);


It's like spaceleft, but with a much larger margin.
.spaceleft
{
    margin-left: 2px;
}

.spaceleft_large
{
    margin-left: 5px;
}


Great stuff!


Now for a "normal" increment button, which will decrement the year by 1. This uses spaceleft.
var btnYearDecTen = document.createElement("div");
btnYearDecTen.classList.add("button");
btnYearDecTen.classList.add("spaceleft_large");
btnYearDecTen.innerHTML = "&#9665;";
bottom.appendChild(btnYearDecTen);

var btnYearDec = document.createElement("div");
btnYearDec.classList.add("button");
btnYearDec.classList.add("spaceleft");
btnYearDec.innerHTML = "&#9664;";
bottom.appendChild(btnYearDec);


Yep. No real surprises, there.


And then we display the year. This is not a control because the user is not supposed to interact directly with it. It's more of a label, and therefore we call it lblYear, and even have a CSS class named the same. We will set its contents to the year potion of selectedDate.
var btnYearDec = document.createElement("div");
btnYearDec.classList.add("button");
btnYearDec.classList.add("spaceleft");
btnYearDec.innerHTML = "&#9664;";
bottom.appendChild(btnYearDec);

var lblYear = document.createElement("div");
lblYear.classList.add("lblYear");
lblYear.classList.add("spaceleft");
lblYear.id = "lblyear_" + id;
lblYear.innerHTML = this.selectedDate.getFullYear();
bottom.appendChild(lblYear);


Not looking great, that's for sure, but nothing a little styling won't cure.


Here we style lblYear by setting the width, height, text alignment and font size. We'll also float left to be consistent.
.calendarContainer select
{
    width: 100px;
    height: 24px;
    border-radius: 5px;
    display: inline-block;
    float: left;
    font-size: 1.6em;
}

.calendarContainer .lblYear
{
    width: 80px;
    height: 24px;
    text-align: center;
    float: left;
    font-size: 1.6em;
}


.spaceleft
{
    margin-left: 2px;
}


Better... much better.


For the last two buttons, I think you should pretty much get the idea by now, so I won't belabor the point.
var lblYear = document.createElement("div");
lblYear.classList.add("lblYear");
lblYear.classList.add("spaceleft");
lblYear.id = "lblyear_" + id;
lblYear.innerHTML = this.selectedDate.getFullYear();
bottom.appendChild(lblYear);

var btnYearInc = document.createElement("div");
btnYearInc.classList.add("button");
btnYearInc.classList.add("spaceleft");
btnYearInc.innerHTML = "&#9654;";
bottom.appendChild(btnYearInc);

var btnYearIncTen = document.createElement("div");
btnYearIncTen.classList.add("button");
btnYearIncTen.classList.add("spaceleft");
btnYearIncTen.innerHTML = "&#9655;";
bottom.appendChild(btnYearIncTen);


Give yourself a pat on the back. You've made through Part 1!


This widget isn't looking at all complete. A datepicker can be a bit of a tricky business, so stay tuned for more.

Next

Displaying days in the current month.

Thursday, 10 January 2019

How I Became An Agency Contractor (Part 1/2)

Further to landing a job at this startup back in 2016, it was not to last. Within half a year, the money ran out and the company was forced to let all its staff go. The boss, the dude who had hired me in the first place, was considerate enough to let us know three months in advance so that we could make preparations. Sure, he was the second employer to let me go in the past year or so, but his conduct was exemplary. There was none of that cost-cutting bullshit, at least. He projected the runway and paid us what we were due, right up to the final month.

The job search begins anew...

On my part, I began my job search anew. This was becoming routine by now. I elected to keep coming into the office to work on the company project even though technically, I wasn't an employee anymore. The boss was still at it, since he was the only one left in the company. In the meantime, I hammered out my website using Semantic UI, which I'd picked up during my time in the startup, and continued blogging.

The job search took a couple months. Apparently, plenty of companies in the immediate vicinity were hiring. On the not-so-bright side, some of these were your typical douchebags trying to smoke me with The Probationary Pay Gambit and not even having the class to be subtle about it. In some of these cases, you could practically smell the desperation. But by then, I was numb to it all and took everything in stride.

It was about this time I interviewed for that job at the IT Training center, and encountered my ex-lecturer. As mentioned, it was an interesting interview, but until I got my ACTA, their hands were tied. It was also around this period I got that ill-fated but educational experience in Mozat. And so the search continued.

An obsession with meaningless things

Among some of the interview offers I got, there was a remarkable phenomenon among Government-affiliated positions, such as Singapore Press Holdings and Singapore Polytechnic. I applied, received replies indicating interest, and then they pulled this stunt whereby they asked for my GCE "O" Level Certification. For those not in the know, the "O" Level Cert is the piece of paper that tells employers that you have graduated from secondary school, i.e., you have a basic education. The "O" stands for "Ordinary".

When I queried if this was an absolute necessity to proceed with the interview, they replied to the affirmative - yes, I absolutely must have that cert. Which was when I politely declined the interview. The HR for SPH, in particular, seemed really shocked in her email. It was like no one had ever had the temerity to turn down an interview for Singapore Press Holdings before. Imagine that! Poor girl.

Some may be wondering why I turned them down over such a trifling matter. It was a chance to work for a big company, wasn't it? To understand this, you'd have to see things from the perspective of a tech person. I wasn't some desperate schmuck with no qualifications looking for just any job. The size of the firm didn't matter. I wanted a tech job for career longevity. And any company that was going to obsess over trivialities such as an "O" Level Cert, certainly wasn't worth my time. Seriously, I had a Bachelor's Degree and multiple Diplomas in related fields and a resume that suggested I'd been through the mill... and these clowns wanted to be absolutely certain I had a basic education?!

This may sound arrogant, but I assure you, hubris has nothing to do with it. In tech, what we value is people who can do the work. Certification is secondary. How many Computer Science grads out there can't solve FizzBuzz, for example?

Do not go there.

The insistence on producing such a trivial piece of documentation told me they were companies that didn't have their priorities right - and if that was the case, no matter how big they were, they were a no-go area. I would work for another startup before joining these big boys, any day of the week.

Also, I think I've paid my dues and have earned the right to say no to bullshit... even if said bullshit is coming from some big-fuck Government-affiliated company like SPH.

Being contacted by an Agency

About the time I was wading through a lot of options, I got contacted by a Recruitment Agency. It was in the form of a message sent to my LinkedIn account. They were hiring for a big tech company, and if I was open to a contract position (one year, renewable), we should talk further.

This got me thinking...

Contract Positions

Now all of my life up to now, I've actively avoid Contract positions due to the perceived lack of job stability. Who wants to be in the position where they're constantly looking for a job? Then I thought further. Constantly looking for a job... like now, you mean? I'd been taking only Permanent roles for the last fifteen years. Fat lot of good it did for career stability! The last two companies I'd had a Permanent role in, tanked. And I was in a position that wasn't too far different from if I had taken on Contract positions to begin with.

No more illusions.

All that "career stability" was an illusion. And I was done with the charade.

Also, in a rapidly evolving field like computer technology, staying too long at any one place was a bad career move unless I was planning to climb some corporate ladder or something. It would be hell on my employability in the long run.

Lastly, I was tired of having to explain why I left my last job. Sure, the fact that the last two companies tanked wasn't my fault. But some companies have this habit of trying to parlay it into something that could be construed as my fault, so as to gain a negotiating advantage. (They didn't know that Your Teochewness doesn't negotiate, and despises the practice.) You know the type - you say your company folded and you can practically see the Fire Sale sign blinking over their heads.


Next

The interview process... and beyond!

Friday, 13 July 2018

Web Tutorial: Styling a Checkbox

The humble checkbox has been a mainstay of the web ever since HTML forms were in existence. Its purpose is to enable the user to select multiple options on a form. It's simple, effective and intuitive.

However, it has one notable flaw - it's pretty much unstylable in CSS. You can't alter the size or appearance of the checkbox. At most, you can make it appear or disappear. That said, for those determined to bend the humble checkbox to your will, being able to make it appear or disappear will be the key to this web tutorial today..

We begin with a bit of HTML incorporating two checkboxes with their respective labels. The first checkbox is labelled "Print" and the second is labelled "Email". Their ids will all also be named accordingly. As an example, we set the first checkbox to be checked by default.

<!DOCTYPE html>
<html>
    <head>
        <title>Checkboxes</title>

        <style>

        </style>

        <script>

        </script>
    </head>

    <body>
        <label for="cbPrint">Print</label>
        <input type="checkbox" name="cbPrint" id="cbPrint" value="print" checked>

        <br />

        <label for="cbEmail">Email</label>
        <input type="checkbox" name="cbEmail" id="cbEmail" value="email">
    </body>
</html>


It's just a plain-Jane checkbox. We're going to make our own soon!


We begin by enclosing each checkbox and its label in a div, and giving the div a class of checkbox_wrapper.
    <body>
        <div class="checkbox_wrapper">
            <label for="cbPrint">Print</label>
            <input type="checkbox" name="cbPrint" id="cbPrint" value="print" checked>
        </div>

        <br />

        <div class="checkbox_wrapper">
            <label for="cbEmail">Email</label>
            <input type="checkbox" name="cbEmail" id="cbEmail" value="email">
        </div>
    </body>


Then we style checkbox_wrapper.

In the main class, we set the cursor property to pointer so that when you mouse over the checkbox or label, it shows the user that this sucker is meant for clicking!

The label within the checkbox_wrapper class has font-size set to 16 pixels. This one's entirely up to you. I'm just making things pretty. I'm awesome like that.

And lastly, the checkbox, which is the input tag within the checkbox_wrapper class, has the display property set to inline. This is entirely unnecessary, because that is the default setting for the checkbox anyway. But we'll need this for later.
        <style>
            .checkbox_wrapper
            {
                cursor:pointer;
            }

            .checkbox_wrapper label
            {
                font-size:16px;
            }

            .checkbox_wrapper input
            {
                display:inline;
            }
        </style>


There shouldn't be significant change at this point, though you may notice that there's some spacing between your checkbox-label pairs, due to the divs they're enclosed in.


Now, before each label, add a div with a class of checkbox. Assign an id which is the id of the respective checkbox, followed by "_checkbox". Within each of these divs, you should have a span element containing "&checkmark;". In the HTML character table, this translates to ✓. A tick!

For a full listing of HTML special characters, here's a link. (https://dev.w3.org/html5/html-author/charref)

        <div class="checkbox_wrapper">
            <div class="checkbox" id="cbPrint_checkbox">
                <span>&checkmark;</span>
            </div>
            <label for="cbPrint">Print</label>
            <input type="checkbox" name="cbPrint" id="cbPrint" value="print" checked>
        </div>

        <br />

        <div class="checkbox_wrapper">
            <div class="checkbox"  id="cbEmail_checkbox">
                <span>&checkmark;</span>
            </div>
            <label for="cbEmail">Email</label>
            <input type="checkbox" name="cbEmail" id="cbEmail" value="email">
        </div>


This is what you should have...

Now style your checkboxes. We'll make it a 20 pixel by 20 pixel square, with slightly rounded corners and a dark grey outline. For good measure, we'll set the float property to left so it aligns with the label.
            .checkbox
            {
                width:20px;
                height:20px;
                border-radius:3px;
                border:1px solid #444444;               
                float:left;
            }


Coming along nicely!


Let's clean this up a little. Set the margin-left property of the labels to 1 em.
            .checkbox_wrapper label
            {
                font-size:16px;
                margin-left:1em;
            }


OK, looking less crowded now.


And here, we'll adjust the tick's span element so it sits nicely within its checkbox. We can accomplish this by setting the display property to inline-block, the width to 100% and aligning the text center. We'll also make the tick bold, and give it a nice lime green.
            .checkbox span
            {
                display:inline-block;
                width:100%;
                text-align: center;
                font-size:1em;
                color:#44FF44;
                font-weight:bold;
            }


Yep, looking presentable now.

Making stuff work

Now you have the checkboxes, but you need to make them respond. First, let's write some JavaScript.

Alter the HTML code as follows. You'll notice that we added an onclick event which calls the checkbox() function, passing in the id of the checkbox as an argument. Also, each div with the class checkbox has had an additional class added to it, either on or off depending on whether the checkbox is checked. This will be significant soon.
        <div class="checkbox_wrapper" onclick="checkbox('cbPrint')">
            <div class="checkbox on" id="cbPrint_checkbox">
                <span>&checkmark;</span>
            </div>
            <label for="cbPrint">Print</label>
            <input type="checkbox" name="cbPrint" id="cbPrint" value="print" checked>
        </div>

        <br />

        <div class="checkbox_wrapper" onclick="checkbox('cbEmail')">
            <div class="checkbox off"  id="cbEmail_checkbox">
                <span>&checkmark;</span>
            </div>
            <label for="cbEmail">Email</label>
            <input type="checkbox" name="cbEmail" id="cbEmail" value="email">
        </div>


And write the checkbox() function. First, grab the div that we styled, using the id and the string "_checkbox".
        <script>
            function checkbox(id)
            {
                var cb = document.getElementById(id + "_checkbox");
            }
        </script>


Next, check if it's checked by accessing its className property.
        <script>
            function checkbox(id)
            {
                var cb = document.getElementById(id + "_checkbox");

                if (cb.className=="checkbox on")
                {

                }
                else
                {

                }
            }
        </script>


If it's checked, set its class to "checkbox off" and ensure that the respective checkbox is unchecked. Do the opposite if it's not checked.
        <script>
            function checkbox(id)
            {
                var cb = document.getElementById(id + "_checkbox");

                if (cb.className=="checkbox on")
                {
                    cb.className = "checkbox off";
                    document.getElementById(id).checked = false;
                }
                else
                {
                    cb.className = "checkbox on";
                    document.getElementById(id).checked = true;
                }
            }
        </script>

Time to test!

Click on the labels or styled checkboxes. Do the original checkboxes respond? They should. We have a problem though... the styled checkboxes themselves aren't responding.

This is because we haven't added styles for On and Off states. Let's fix this. For the Off state, span disappears. For the On state, span is visible.
            .checkbox span
            {
                display:inline-block;
                width:100%;
                text-align: center;
                font-size:1em;
                color:#44FF44;
                font-weight:bold;
            }

            .checkbox.off span
            {
                display:none;
            }

            .checkbox.on span
            {   
                display:inline-block;
            }


And here you go!


One final touch. Hide the checkboxes.
            .checkbox_wrapper input
            {
                display:none;
            }


Voila.

Try it here...





Isn't that an awful lot of trouble?

Well yeah, no shit. These are the hoops HTML/CSS makes you jump through to style textboxes. Still, if you want a nicer-looking UI, this is what it takes.

It's worth noting that many CSS frameworks such as Semantic UI already do this for you, and all the styling and JavaScript has already been written in the package. But nothing like learning how to do it yourself, hey?

That's all. ✓ back for more! (snicker)
T___T

Tuesday, 11 July 2017

Five comparisons between Twitter Bootstrap and Semantic UI

There are plenty of CSS and layout frameworks on the market. I've had the privilege of using two of them - Twitter Bootstrap and Semantic UI. Both frameworks are used to provide responsive layouts and improve the UI. While they're similar in very basic ways, they are different enough to warrant a comparison.



Here are 5 ways they compare...

1. Features

Both Twitter Bootstrap and Semantic UI use a grid layout for responsiveness. Twitter Bootstrap uses as 12-column grid while Semantic UI uses a default of 16 columns (which can be changed). Some say this increased granularity gives Semantic UI the edge, but from my perspective I'm not sure it makes that much of a difference.

They both have features like button groups, accordions and beautified form inputs. This is where Semantic UI arguably has the advantage, as it boasts many more variations on those features than Twitter Bootstrap. Semantic UI's icon set, for example, has about 617 in 25 categories to Twitter Bootstrap's 264... the free ones anyway.

Twitter Bootstrap's icon set (left)
Semantic UI's icon set (right)

Both Twitter Bootstrap and Semantic UI offer features that the other do not. For example, Twitter Bootstrap has a Jumbotron feature, and Semantic UI has a really nifty-looking rotating cube feature. But even on quantity alone, Semantic UI has the obvious edge.

2. Marketability

Twitter Bootstrap is almost a household name among developers. Most devs have used it since 2011, at one time or other, to do up websites. Semantic UI, on the other hand, is the relative new kid on the block, having been here since only 2015, and at this time does not even have a Wikipedia entry.

The obvious inference here, of course, is that Twitter Bootstrap has way more support and documentation.

I know Bootstrap!

But the real edge is that almost everyone has heard of Twitter Bootstrap, whereas fewer have heard of Semantic UI. So putting Twitter Bootstrap on your resume is more likely to get you jobs. Even during interviews, I've had interviewers nod sagely when I mentioned Twitter Bootstrap, and give me blank looks when I mentioned Semantic UI.

If you mention Twitter Bootstrap, most people will immediately assume you understand Responsive Design. Which isn't strictly true, but perception is what it is.

3. Look-and-feel

Twitter Bootstrap isn't considered generic without good reason. Most people use the free default theme, which results in Every Fucking Bootstrap Website Ever. Which can be a shame because Twitter Bootstrap can look really good, if you're willing to pay for different themes. Even if not, contributors have offered their own Twitter Bootstrap themes, which can add some variety.

Semantic UI's default and optional themes, all free of charge, already promise a dizzying array of effects that won't immediately scream SEMANTIC to people who view them. Of course, the fact that Semantic UI isn't famous like Twitter Bootstrap, probably helps.

Twitter Bootstrap's color scheme (top)
Semantic UI's color scheme (bottom)

If you want hard numbers though, just consider color schemes. Twitter Bootstraps default theme comes with 6 colors. Semantic UI has 12 (in both cases, we're not counting black). And this can be a simple but huge factor in flexibility of design.

Also, Twitter Bootstrap has 4 size categories - lg (large), md (medium), sm (small) and xs (extra small). Semantic UI has 8 of them - massive, huge, big, large, medium, small, tiny and mini. Though it's worth noting that Semantic UI's size categories aren't rendered with perfect consistency throughout their elements.

4. Difficulty level

Twitter Bootstrap is easier for someone with totally no jQuery knowledge, to use effectively. For Semantic UI, it's a lot harder because jQuery is used often, either as an initializer or to manipulate the controls. Even though many features have a non-jQuery version, this results in a drastically less rich user interface.

If you're only using Twitter Bootstrap or Semantic UI for responsiveness, then this doesn't matter.

Semantic UI's code sample

Personally, I like Semantic UI's style. The jQuery animation features in its feature set allows me to do a lot of cool things without actually writing my own.

Although if you want to really customize stuff, it might be easier in Twitter Bootstrap. Semantic UI offers a lot of customization options, but it can't cover everything and sometimes trying to shoehorn their existing options into what you want exactly, is a pain in the ass.

5. Class names

Twitter Bootstrap uses class names that don't read like normal English.
<div class="row">
    <div class="col-xs-12 col-sm-6 col-md-8">Column 1</div>
    <div class="col-xs-6 col-md-4">Column 2</div>
</div>


Semantic UI's class names look like this.
<div class="row">
    <div class="twelve wide computer six wide phone eight wide tablet column">Column 1</div>
    <div class="six wide computer four wide tablet column">Column 2</div>
</div>


Some say this makes Semantic UI friendlier to use. I'm ambivalent here. See, I have this habit of writing my own CSS classes. And it's far harder to clash with CSS class names like btn-lg than with names like segment or basic.

Conclusion

Personally, I'd take Semantic UI any day of the week. It's got features I need, and I don't have a problem with using jQuery. But Twitter Bootstrap might be better for people who want decent results with a minimum of fuss, and more if they're willing to cough up the cash. And in any given professional environment, the chances of Twitter Bootstrap being already in use are astronomically higher.

Pick up a CSS framework today. It's a xs effort for massive gains.
T___T