Skip to content

Instantly share code, notes, and snippets.

@dzenkovich
Created October 21, 2013 07:39
Show Gist options
  • Save dzenkovich/7079976 to your computer and use it in GitHub Desktop.
Save dzenkovich/7079976 to your computer and use it in GitHub Desktop.
JS Core: Task 3. Currency Converter
/**
* This self-invoking anonymous function consists of:
* - the object currencyConverterTool, which is responsible for conversion of usd values into euro values and displaying the result in the tooltip;
* - the helper function for adding event listeners;
* - the Tooltip constructor.
* It encloses variables and functions in it's scope and helps us keep them out of Global
* This is the most simple scenario of Module pattern.
*/
(function(){
/**
* Helper function to create event listeners
* @param element - DOM object that is the event target
* @param event - a string representing the event type to listen for
* @param func - the event listener function that is called when the event occurs
*/
function addEvents(element, event, func){
if(element.addEventListener)
{
/* uses for FF, Chrome, Safari, Opera;
"false" parameter shows that the "bubbling" order is used for firing events */
element.addEventListener(event, func, false);
}
else if(element.attachEvent)
{
element.attachEvent('on' + event, func); //uses for IE8-
}
}
/**
* The object which manages the converting actions on the page,
* it uses Singleton pattern as there is no need to create more than 1 object for these purposes
*/
var currencyConverterTool = {};
/**
* Gets the selection text value and its coordinates
* @returns {{text: string, xCoord: number, yCoord: number}}
*/
currencyConverterTool.getSelectedText = function () {
var selection= '', range, rect, x = 10, y = 10;
if ((window.getSelection) || (document.getSelection)){ // if not IE
selection = (window.getSelection) ? window.getSelection() : document.getSelection();
range = selection.getRangeAt(0).cloneRange(); //creates the copy of the fragment of the document (Range object) based on the selection
if (range.getClientRects) {
rect = range.getClientRects()[0]; //returns the 1st element from the collection of rectangles that represents the area of the screen occupied by the range
x = rect.left; //gets the left position of the selection
y = rect.top; //gets the top position of the selection
}
}
else if (document.selection){ //IE8-
selection = document.selection.createRange().text;//IE browser gives its own interface of interaction with the selection - it is the object "selection" in the scope of document object. The "selection" variable contains the text of user's selection
range = document.selection.createRange(); //returns the TextRange object
x = range.boundingLeft; //gets the left position of the selection
y = range.boundingTop; //gets the top position of the selection
}
return {
text: selection.toString(),
xCoord: x,
yCoord: y
}
}
/**
* Converts USD value into Euro and shows the tooltip near the selection in the text
*/
currencyConverterTool.showConverterBox = function () {
/**
* The function converts USD price into Euro
* @param usd - USD price
* @returns {string} - converted Euro price
*/
function convertUsdToEuro (usd) {
return (usd / 1.3).toFixed(2); //convert to string and leave only 2 digits after dot.
}
/**
* Inserts the received USD and Euro values into the tooltip and shows the tooltip box
* @param usdValue - USD value for conversion
* @param euroValue - EURO value
* @param xCoord - left position of the selection
* @param yCoord - top position of the selection
*/
function showTooltip (usdValue, euroValue, xCoord, yCoord) {
var childrenElements, //inner elements in the tooltip box
tooltipBox;
//creates Tooltip object if it doesn't exist
if (!currencyConverterTool.toolTip) {
currencyConverterTool.toolTip = new Tooltip ();
tooltipBox = currencyConverterTool.toolTip.tooltipBox;
document.body.appendChild(tooltipBox );
childrenElements = tooltipBox.childNodes;
//loops through the all children elements of the tooltip box
for( var i = 0 , len = childrenElements.length; i < len ; i++ ){
if ( childrenElements[ i ].className === 'usdValue' ) {
currencyConverterTool.toolTip.usdElement = childrenElements[ i ];
}
if( childrenElements[ i ].className === 'euroValue' ){
currencyConverterTool.toolTip.euroElement = childrenElements[ i ];
}
}
}
currencyConverterTool.toolTip.usdElement.innerHTML = usdValue;
currencyConverterTool.toolTip.euroElement.innerHTML = euroValue;
currencyConverterTool.toolTip.show(yCoord, xCoord);
}
var selectedText = currencyConverterTool.getSelectedText().text, //text of the selection
trimedString = selectedText.replace(/^\s+|\s+$/g, ''), //the value of selection when all spaces before and after selection were removed
euroValue, usdValue,
xCoord = currencyConverterTool.getSelectedText().xCoord,
yCoord = currencyConverterTool.getSelectedText().yCoord;
//check if there is a "$" sign before or after the selection value
if (/^\$/.test(trimedString) || /\$$/.test(trimedString)) {
usdValue = +trimedString.replace(/[\$,]+/g, ''); //remove dollar sign and comma from selection
if (usdValue.valueOf() === parseFloat(usdValue)) { //check if the selected usd value is a number
euroValue = convertUsdToEuro(usdValue.valueOf()); //converts the USD value
showTooltip(usdValue, euroValue, xCoord, yCoord);
}
}
}
/**
* Hides the tooltip box
*/
currencyConverterTool.removeConverterBox = function () {
if (currencyConverterTool.toolTip) {
currencyConverterTool.toolTip.hide();
}
}
/**
* Constructor function for the tooltip element in the DOM
* @constructor
*/
function Tooltip () {
var self = this; //this variable is created to use the Tooltip object reference in the inner function
self.tooltipBox = {};
/**
* Creates DIV element, sets class name to it and forms its child elements. It runs when the object is created
* @private
*/
function _create () {
self.tooltipBox = document.createElement('div');
self.tooltipBox.className = 'tooltip';
self.tooltipBox.innerHTML = '$' + '<span class="usdValue"></span> = &euro;<span class="euroValue"></span>';
}
_create();
}
/**
* This function is the property of the Tooltip "class", which is shared by all its instances. Such approach saves memory, as every instance uses common function.
* The function calculates the position of the tooltip box and makes it visible
* @param top - top position of the selection
* @param left - left position of the selection
*/
Tooltip.prototype.show = function (top, left) {
var tooltipBoxHeight = this.tooltipBox.offsetHeight, // gets the visible height of the element in pixels: it contains the height with the padding, scrollBar, and the border, but does not include the margin
tooltipBoxWidth = this.tooltipBox.offsetWidth, //gets the visible width of the element in pixels: it contains the width with the padding, scrollBar, and the border, but does not include the margin
windowWidth = (window.innerWidth) ? window.innerWidth : document.documentElement.clientWidth; //get the width of the window
//Sets the top position of the tooltip element: if there is not enough space for the tooltip box above the selected text it is displayed below it. Otherwise it stays above.
this.tooltipBox.style.top = (top - tooltipBoxHeight - 5 > 0) ? top - tooltipBoxHeight - 5 + 'px' : top + 20 + 'px';
//Sets the left position of the tooltip element: if there is not enough space for the tooltip box between the left border of the selected text and the right border of the document it is alined by the right border of the selection.
//By default it is aligned by the left side of the selection.
this.tooltipBox.style.left = (left + tooltipBoxWidth < windowWidth ) ? left + 'px' : windowWidth - tooltipBoxWidth - 5 + 'px';
this.tooltipBox.style.visibility = 'visible'; // makes the tooltip box visible
}
/**
* Makes the tooltip box invisible
*/
Tooltip.prototype.hide = function () {
this.tooltipBox.style.visibility = 'hidden';
}
/**
* Runs when the DOM is loaded
*/
function setConverterTool() {
addEvents(document, 'click', currencyConverterTool.removeConverterBox);
addEvents(document, 'contextmenu', currencyConverterTool.showConverterBox);
}
addEvents(window, 'load', setConverterTool);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment