Saturday, March 19, 2016

People Search Filters Missing in Bing Search

People Search Filters Missing in Bing Search
Biggest problem with Bing search Engine is that, they are busy copying Google features without a thought in head. People search is an example that supports this fact. Search results layout for a person name in Google and Bing is almost the same. Good thing is that by keyword, both search engines know that, end user is searching for a person, at least. But, the most important thing, effectiveness of search results is diminished by missing person filters.  

Figure 1. Bing Search results for a person name.

Figure 2. Google Search results for a person name.

Figure 3. Suggested dynamic filter features for search results page – action: search person name.

As per Thurow and Musica (2009), while studying a search engine, its effectiveness, efficiency, learnability, memorability, error prevention & recovery and satisfaction is taken into account. By copying Google as described in Figure 1 and Figure 2 above, Bing Search Engine is trying to cater learnability only. There should be something more Bing must plan to cater to go above and beyond Google. With dynamic filtering suggestion described in Figure 3 above, Bing could achieve better effectiveness and satisfaction.

References

Thurow, S., & Musica, N. (2009). When Search Meets Web Usability. Retrieved March 19, 2016, from http://deca.cuc.edu.cn/Community/cfs-filesystemfile.ashx/__key/CommunityServer.Components.PostAttachments/00.00.00.11.64/When.Search.Meets.Web.Usability.pdf

Google Calendar Won’t Let You Print All Search Results

This is a very common use case, where you want to print large number of events in Google Calendar. But print view of this tool is not optimized for printing. Suppose, a user has many (33 in current example in Figure 1 below) events upcoming for a search keyword, if he tries to print the results, he may only get few of the events (13 in the Figure 1 example below) in the paper print he takes.
Figure 1. Google Calendar is not optimized for printing.
As per Leavitt and Shneiderman (2013), dimensions of content should be adjusted to fit most common page size while printing. But Google Calendar print style sheet is not smart enough to remove scroll bars while printing.

References
Leavitt, M., & Shneiderman, B. (2013). Research-Based Web Design & Usability Guidelines. Retrieved March 19, 2016, from http://www.usability.gov/sites/default/files/documents/guidelines_book.pdf

Author Commentary Options Missing in Blogger

According to research by Salas-Rueda (2016), audio-visual content facilitates the teaching-learning process. Blogger gives the facility to insert a YouTube video, as mentioned in Figure 1. But, the steps involved in attaching a video may be, publishing a video (lengthy process in itself) and then refer it here.  
Figure 1. Option to attach video in Blogger.com with possible improvement.
As per Nielsen (1995), a system should cater both inexperienced and experienced users. Had there been a webcam option in Blogger for videos, it would have been more flexible and efficient to use.

References
Nielson, J. (1995, January 1). 10 Usability Heuristics for User Interface Design. Retrieved March 02, 2016, from https://www.nngroup.com/articles/ten-usability-heuristics/
Salas-Rueda, R. (2016). The impact of usable system for regression analysis in higher education. International Journal of Educational Technology in Higher Education, 13(1), 1-10.

Sunday, March 13, 2016

Strictly JavaScript Income Tax Calculator


This example explains how to use the right conditions at right place.

"use strict"; //  undeclared variables prohibited.
var $ = function (id) {
    return document.getElementById(id);
};



window.onload = function () {
    $("calculate").onclick = calculateTax;
    $("reset").onclick = resetInputValues;

};
// this method is called on click of reset button
function resetInputValues() {
    $("tax").value = "";
    $("income").value = "";
    $("mymessage").innerHTML = "";
    return;
}

// this method is called on click of calculate button
function calculateTax() {
    //input validation
    var mySalary = $("income").value.trim();
    if (isNaN(mySalary)) {
        window.alert("Invalid input.");
        return;
    }
    mySalary = parseFloat(mySalary);

    var taxPaid = 0;

    if (mySalary > 413200) {
        taxPaid = (mySalary - 413200) * 0.396 + 119996.25;
    }
    else if (mySalary > 411500) {
        taxPaid = (mySalary - 411500) * 0.35 + 119401.25;
    }
    else if (mySalary > 189300) {
        taxPaid = (mySalary - 189300) * 0.33 + 46075.25;
    }
    else if (mySalary > 90750) {
        taxPaid = (mySalary - 90750) * 0.28 + 18481.25;
    }
    else if (mySalary > 37450) {
        taxPaid = (mySalary - 37450) * 0.25 + 5156.25;
    }
    else if (mySalary > 9225) {
        taxPaid = (mySalary - 9225) * 0.15 + 922.50;
    }
    else {
        taxPaid = mySalary * 0.10;
    }

    $("tax").value = taxPaid.toFixed(2);
    $("mymessage").innerHTML = taxPaid + " is rounded to " + $("tax").value;

}



Sample strictly JavaScript Monthly Balance Calculator


Save this folder somewhere you can edit and play around with these files.

Some  of the learning :

1. how to set undeclared variables prohibited
2. handle arrays
3. playing around with dates in jacascript. new Date, setYear, setMonth, setDate, getDateParts, getFullYear, getMonth, getDate
Especially the formatting.
4. classes and objects in JavaScript
5. parseInt, parseFloat

and so on

balance.js:

"use strict"; //  undeclared variables prohibited.

// get element by id
var $ = function (id) { return document.getElementById(id); };

//creates the grid to display based on transList array available in memory ctrl F5 to start over.
var updateDisplay = function () {
    var html = "<tr><th>Date</th><th>Amount</th><th>Balance</th></tr>";
    var html = html.concat("<tr><td></td><td></td><td>0</td></tr>"); // initially balance is zero.

    var count = getTransaction();//get number of elements in transList array.
    var total = 0;

    //itrate transList to create actual transaction grid
    for (var i = 0; i < count; i++) {
        var trans = getTransaction(i);//get i+1 element in transList array.
        total = calculateBalance(trans["type"], trans["amount"], total);//get cumulative balance after current transaction.
        //system allows blank value in date, if blank is passed as input, itmeans current date. If type is withdrawal amount is displayed like, (amount).
        // date format id  MMM DD YYYY ( e.g. Feb 29 2016). future and past dates are allowed.
        html = html.concat("<tr><td>", trans["dateDisplay"], "</td><td>", trans["amountDisplay"], "</td><td>", formatTotal(total), "</td></tr>");
    }
    // set the html calculated to UI.
    $("transactions").innerHTML = html;

};

//if date input field is blank(noTrim) , it means user wants to enter current date
var getValidDateString = function () {
    var dtParts; //undefined
    //if user wants current date
    if ($("date").value === "") {
        dtParts = getDateParts();
    } else {
        dtParts = getDateParts($("date").value);
    }
    //if user wants current date, almost no chance that dtParts remains undefined
    //but if user enters some value it must be a valid date in format MM/DD/YYYY or else dtParts is undefined
    if (typeof dtParts !== "undefined") {
        //return valid date entered/ assumed in format MMM DD YYYY
        return months[dtParts[0] - 1] + " " + ((dtParts[1] < 10 ? "0" : "") + dtParts[1]) + " " + dtParts[2];
    }
    alert("Please enter date in format MM/DD/YYYY e.g. 02/28/2017. You may leave blank if transaction happened today.");// Instrictions
    $("date").focus(); // take user to date input field to re-enter.


};


// there is almost no chance of error here, since dropdown has only two options
var getValidType = function (type) {

    if ($("type").value === "deposit" || $("type").value === "withdrawal")
        return $("type").value;

    alert("Invalid Type.");
    $("type").focus();

}
//if user enters some random text or he tries to give negative values, this will throw alert.
var getValidateAmount = function () {

    //check if not a number.
    if (isNaN($("amount").value)) {
        alert("Invalid amount.");
        $("amount").focus();
        return;
    }
    //round to two decimals
    var returnValue = parseFloat($("amount").value, 10).toFixed(2);//string here to return
    //negative value not allowed, since it means withdrawal, denoted by transaction type
    if (parseFloat($("amount").value, 10) < 0) {
        alert("If it is a withdrawal, select withdrawal in Type dropdown and enter a positive amount here.");
        $("amount").focus();
        return;
    }
    return returnValue;
}

var add = function () {
    var cType = getValidType();
    var cAmount = getValidateAmount();
    var cDateString = getValidDateString();
    if (typeof cType === "undefined" || typeof cAmount === "undefined" || typeof cDateString === "undefined")
        return;
    //till this point we are ready with valid inputs(assumed/actual).
    addTransaction(cType, cAmount, cDateString);
    //now update display to include just added transaction.
    updateDisplay();
};

//bind add function to click of add button on load of window
window.onload = function () {
    $("add").onclick = add;
    updateDisplay();

};

library_balance.js

"use strict"; //  undeclared variables prohibited.

//no form input fields reffered here to make it look like a library.

var transList = []; // array to store transactions

// short form of months to be displayed. This is needed because old browsers don't support toLocaleDateString
//can't use substring on date string, because it contains "," which is not presented in date in screenshot
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

//transaction is the class will be used to insert objects in transList
function transaction(type, amount, date) {
    this.type = type; // deposit or withdrawal  - string
    this.amount = amount; //string
    this.amountDisplay = (type === "deposit") ? amount : "(" + amount + ")"; // display (amount) for withdrawal
    this.dateDisplay = date;//date is already validated and converted to format to be displayed

};


//if input is undefined, it will consider current date as input
//input is string/nothing
//outout is  01/01/2001 >  [ 1, 1, 2001] ie. [ month, day, year]
var getDateParts = function (dateValue) {

    if (typeof dateValue === "undefined") {
        var currentdate = new Date();
        //month is done + 1 because it returns one less number than actual month e.g. 2 for march
        return [currentdate.getMonth() + 1, currentdate.getDate(), currentdate.getFullYear()];
    }
    var datereg = /^\d{1,2}\/\d{1,2}\/\d{4}$/; //e.g.  99/99/1111
    if (dateValue.match(datereg)) {
        var splitDateInput = dateValue.split("/");
        var monthPart = parseInt(splitDateInput[0], 10);// e.g. 99
        var dayPart = parseInt(splitDateInput[1], 10);// e.g. 99
        var yrPart = parseInt(splitDateInput[2], 10);// e.g. 1111
        var date = new Date();// gives current date
        date.setYear(yrPart);
        date.setMonth(monthPart - 1);
        date.setDate(dayPart);
        // now test data ( 99/99/1111) gives date as Sat Jun 07 1119 00:00:00 GMT-0400 (Eastern Daylight Time)
        //so now compare with inputs again.
        //good thing is leap check is also done in below if condition, like 02/29/2015 will fail here.
        if (date.getFullYear() === yrPart && date.getMonth() + 1 === monthPart && date.getDate() === dayPart) {
            return [monthPart, dayPart, yrPart];
        }
        //if input was valid ,an array containing month, day , year numbers is returned
        //or else nothing - undefined

    }

}

//input integer/nothing
//output is a transaction object
var getTransaction = function (index) {
    if (typeof index === "undefined") {
        return transList.length;
    }
    else if (index < transList.length) {
        return transList[index];
    }



};

//now add transaction is simple, inputs must be valid, simply add an object of type transaction to transList
//input string, string , string
var addTransaction = function (type, amount, date) {

    transList.push(new transaction(type, amount, date));
};

//this adds amount to total for deposit
// and subtract amount from deposit for withdrawal
//input string, string, string
//output string
var calculateBalance = function (type, amount, total) {
    //amount = parseFloat(parseFloat(amount, 10).toFixed(2), 10);
    // total = parseFloat(parseFloat(total, 10).toFixed(2), 10);
    amount = parseFloat(amount, 10);
    total = parseFloat(total, 10);
    if (type === "deposit")
        return (total + amount).toFixed(2);
    else
        return (total - amount).toFixed(2);
};

//used to format any string like  -23.2222 to (23.22)
//or 23.2222 to 23.22
var formatTotal = function (am) {

    am = parseFloat(am, 10);

    return (am < 0) ? "(" + Math.abs(am).toFixed(2) + ")" : am.toFixed(2);


};









Sample Custom jQuery plugin


  1. Download  this folder somewhere you can open and edit the content
  2. On $(document).ready , decorateTable custom jQuery plugin is applied on table with id "important" . This will apply even odd classes on the elements of this table . This custom plugin has three input settings parameters $('#important').decorateTable({ oddRow: 'oddAltered', evenRow: 'evenAltered', headerRow: 'headerAltered' });
  3. default settings for custom plugin are : oddRow: 'odd',  evenRow: 'even', headerRow: 'header'

altrow.js

"use strict";

$(document).ready(function () {
    $('#important').decorateTable();
    // if you want to give custom colour, give parameteres as mentioned below.
    // $('#important').decorateTable({ oddRow: 'oddAltered', evenRow: 'evenAltered', headerRow: 'headerAltered' });
});

jquery.altrow.js

"use strict";
(function ($) {

    $.fn.decorateTable = function (options) {

        // default settings
        var settings = $.extend({
            oddRow: 'odd',
            evenRow: 'even',
            headerRow: 'header'
        }, options);

        // odd rows not having th element 
        //in table this (on which decorateTable plugin is applied)
        $('tr:not(":has(th)"):odd', this).addClass(settings.evenRow); // class name is swithed to make it look like screenshot in the assignment
        // even rows not having th element
        //in table this (on which decorateTable plugin is applied)
        $('tr:not(":has(th)"):even', this).addClass(settings.oddRow); // class name is swithed to make it look like screenshot in the assignment
        //the row having th element (on which this plugin is applied)
        $('tr:has(th)', this).addClass(settings.headerRow);



    }

}(jQuery));



Simple example of $.ajax to get JSON (JQuery)



  1.  Download the files available in folder speakers
  2. Save them somewhere you can access them over http.
  3. On document ready, toobin.json is loaded and html elements inner html is replaced.
  4. On click of elements in navigation chua.json, sampson.json, sorkin.json or toobin.json is loaded using  $.ajax and elements in index.html are filled with html. Which json to load is being decided by title attribute of of the anchor clicked.
speakers.js

"use strict"; 
$(document).ready(function () {

    //applies to all aside > nav > ul > li > a
    $("aside > nav > ul > li > a").click(function () {
    
        //fill this array with parts of json file path. please note, with json file location change, you will change it.
        var pathparts = [];
        pathparts.push(
          "json_files/",
          $(this).attr('title'),
          ".json"
          
        );
     
        consumeJSON(pathparts.join(""));

    });
    //anchor with title toobin
    $("a[title='toobin']").click();
}); // end ready

function consumeJSON(jsonFileURL) {
    $.ajax({
        url: jsonFileURL,
        //default method is GET so need not mention
        dataType: "text", // you may pass json here and avoid parseJSON below
        success: function (data) {

            //data downloaded so we call parseJSON function 
            //and pass downloaded data
            var json = $.parseJSON(data);
            //use html() instead of text() below, note that input has html tags too. see the json also to observe these tags.
            //each json has single element under speakers collection
            // important : we could also prepare whole html and set html inside main element
            $("main > h2").html(json.speakers[0].month + "<br/>" + json.speakers[0].speaker);
            $("main > h1").html(json.speakers[0].title);
            $("main > img").attr("src", json.speakers[0].image);
            $("main > p").html(json.speakers[0].text);
        }
    });
}