Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Wednesday, 30 October 2013

Javascript snippet to HTML encode foreign characters

This Javascript snippet is useful for converting characters in a language like Arabic to HTML Encoding for putting on web pages.

var a = "السلام عليكم"; //Arabic for Peace Be Upon You (Hello)
var h = a.replace(/(.)/g, function($1){
   return ($1 == " ") ? $1 : "&#" + $1.charCodeAt() + ";";
});

The variable h now holds السلام عليكم
a.replace(/(.)/g, function($1){
  if ($1 == " ")
    return " ";
  else
    return "&#" + $1.charCodeAt() + ";";
})
"السلام عليكم"
"السلام عليكم"
"السلام عليكم"
"السلام عليكم"
console.log("السلام عليكم".replace(/(.)/g, function($1){
  if ($1 == " ")
    return " ";
  else
    return "&#" + $1.charCodeAt() + ";";
}));

Tuesday, 19 March 2013

A naturally placed DIV that responsively expands to browser window/viewport height

Have you ever seen those web applications that have a pane on the left hand side and a main body and somehow it fits it all into the size of your browser window (viewport) what ever browser/device you use or screen size you have and it doesn't show your browser's scroll bars? I'm talking about the height of the left pane and the body adjusting automatically to the height of your browser window.

Have you ever tried searching for how they do it? I tried and couldn't find a straight answer. I'm no javascript nerd so I had to figure this out the hard way with trial and error. To save any of you some time here is my solution using a little CSS and some responsive javascript (jQuery):

Scenario:

I have a typical page with a banner at the top and a navigation bar just below it, and I want my web application-style left pane and main body pane to fit into the vertical white space of the page body that is not already occupied by the banner or navigation bar. My HTML looks a little like this:

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css.css">
<script src="jquery.js"></script>
<script src="js.js"></script>
</head>
<body>
<div id="container">

<div id="banner"></div>
<div id="nav"></div>

<div id="webapp">
  <div id="leftpane"></div>
  <div id="mainbody"></div>
</div>

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

So, for this example, my main concern is the #leftpane div. If you understand the code for that, you can duplicate the approach for the #mainbody. (To be honest, I'm writing this post here before I tackle mainbody next)

The CSS for leftpane is:

#leftpane{
  margin:0 auto;
  float:left;
  border:1px solid darkgreen;
  background-color:rgba(0, 0, 150, .15);
  vertical-align:top;

  width:30%;
  overflow-y:auto;
}

Notice there is no mention of position:absolute. That's because this example is NOT about filling the page from top to bottom with the left pane. If you want that kind of information, then google will easily find you that. Instead, what we are doing here is having the top of the div element be in its normal position, while the bottom border of the div will expand vertically depending on the size of the window/viewport. I only care about the height of the div in my example. Widths are managed with width: n% and using min-width:n px, but I will not discuss widths any further.

Anyway. How do we get the leftpane to expand according to size of the window? With a bit of Javascript (jQuery). The  javascript below is responsive. When the page first loads it calls the snapLeftpane() function and resizes the leftpane and then if the user makes their window bigger or smaller, it calls the snapLeftpane() function again to resize the leftpane again.

But I set some limits. If the window becomes too small, like if the user is messing about and makes their browser window too small, then it snaps the leftpane to the minimum height allowable. And in the opposite situation, when the user has a huge window, it limits the height of the leftpane to the maximum height allowable, so the web app doesn't look ridiculously disproportioned.

Here's the javascript:

function snapLeftpane(){
    var minHeight = 450,
        maxHeight = 800,
        wHeight = $(window).height();
    var el = $('#leftpane');
    if(el.length){
        var top = el.offset().top + 5;
    if(wHeight
>=  minHeight && wHeight <= maxHeight) {
        el.height((wHeight - top) + "px");
        console.log('naturally expanding height ' + el.height());
    } else if (wHeight
> maxHeight) {
        el.height(maxHeight + "px");
        console.log('set to max height ' + el.height());
    } else if (wHeight
< minHeight) {
        el.height(minHeight + "px");
        console.log('set to min height ' + el.height());
    }

    }
}

$(window).on('resize load', function(){snapLeftpane();});


And if you run this code in your browser and play around with the size of the browser window, you will see how it adjusts the height of the left pane accordingly or snaps it to the minimum height or maximum height if you make the window too small or too large. I recommend you modify the min and max heights to your preferences.

That's it. Hope this helps :)

Sunday, 18 December 2011

The Very Simple JavaScript Formula Class

A small Javascript program I wrote a while back but didn't get round to releasing until now.

The Very Simple JavaScript Formula class takes a simple string of characters written with a standard keyboard and translates it into HTML code that attempts to visually represent the mathematical notation. The purpose of this class is to make maths on the web easier to write, display and understand - users won't need to learn LaTeX or other markup languages or use desktop/server-side applications to create visual Formulas. All you need to do now is type the formula and VSJSFormula will display the rendered formula. The source code is at:
http://code.google.com/p/vsjsformula/

Tuesday, 18 January 2011

Buggy JavaScript Regex and parsing speeds in Firefox, Chrome, Opera and IE6

I was working on a little section of a small javascript application I'm writing when I came across this issue and I've decided it's worthy of documenting in the public domain.

The problem: This Javascript fragment of a regular expression replace statement requires exponential run-time to parse a string the longer it gets:

input.replace(/([^\s]+)*&radic;\{(.*?)\}/gi, '<sup>$1</sup>&radic;<span class="ol">$2</span>')

It replaces an example string - "&radic;{123}" - with this - "<sup></sup>&radic;<span class="ol">123</span>".

But with each additional character added inside the curly braces the time taken to replace it increases exponentially. I have 4 browsers installed on my system - Firefox 3.6.13, Google Chrome 5, Opera 11 and Internet Explorer 6. I haven't upgraded IE6 to the latest version because I use it to test how websites look for people using business/government computers whose technology department haven't upgraded the browsers in 10 years! (Shame on you!)

The results are surprising to say the least. The table and charts below show how long it took (in milliseconds) for each browser to parse a string with 1 to 20 characters inside the curly braces and output it to the screen.


 
Str Length Time FF Time CH Time OP Time IE6
1 5 0 0 0
2 5 1 0 0
3 5 0 0 0
4 6 1 0 0
5 8 1 0 0
6 12 1 0 0
7 19 1 0 0
8 33 3 0 0
9 60 5 0 0
10 115 8 0 0
11 224 17 0 0
12 448 35 0 15
13 892 71 0 0
14 1773 143 0 0
15 3544 286 0 15
16 7113 576 0 0
17 14167 1146 0 31
18 28356 2287 0 47
19 58691 4593 0 94
20 113196 9159 0 188




The results are very surprising. At 13 characters long, the browser suddenly starts becoming very slow and a pattern becomes apparent - that the time taken to execute the regex statement is taking exponentially longer.

IE6 only really starts doing this at 17+ characters but is, surprisingly, faster that both Firefox and Chrome! IE6 faster than Chrome! OMG! Oddly, IE6 spontaneously spikes to 15ms every now and again before reaching 17 characters whether 1 or 16 characters are entered.

Another thing to note is that Chrome is more than 10x faster at doing this than Firefox. The JagerMonkey needs to go on a JagerDiet.

What is even more surprising than that is that execution time in Opera is very close to 0ms and does not rise at all! In Opera this operation isn't exponential! I tested it with over 100 characters and performance in Opera is amazing going above no more than 1ms. (Much respect to the Opera Dev team and their Carakan engine!)

When I made this mistake I was really surprised why it took so long but quickly realised my mistake. I can't really explain what's going on under the hood of the regex engine (because I don't really know in that much detail) but I identified the bug in my regex and solved the problem, which is the single asterisk (*) highlighted:

input.replace(/([^\s]+)*&radic;\{(.*?)\}/gi, '<sup>$1</sup>&radic;<span class="ol">$2</span>')

and which should be replaced with a question mark to solve the problem.

input.replace(/([^\s]+)?&radic;\{(.*?)\}/gi, '<sup>$1</sup>&radic;<span class="ol">$2</span>')

What the regex code is doing, and don't blame me if I'm wrong - I'm no expert - is that when you use the * operator it checks to see if the pattern before it exists and it does this by trying to match the whole length of the string with the pattern [^\s] (which means any character but empty space) and then it reads the string one character at a time until it reaches the end and then it back tracks the length of the string to the beginning. It's a greedy operator which tries to find the longest possible matching string. After that, the rest of the regex is interpreted accordingly.

When you replace * with a ? it checks to see if there's anything before &radic; and if there isn't it simply moves on to carry out the rest of the regex. It only checks one character minimum before it moves on while using * checks the length of the string with each character it moves along. That's why using * becomes slow the longer the string gets.

I think the reason Opera is not affected by this coding bug is because their internal regex engine identifies the bug and realizes that it's stupid for the greedy operator to check the whole string when the next regex pattern after it matches instantly so internally it treats the * operator like a ? operator, thus reducing execution time. They have very clever people at Opera. Mozilla and Google should really think about incorporating this performance increasing technique into their own engines.

Thursday, 24 September 2009

Kohana PHP framework - some tips

Recently, I've been working with the Kohana PHP Framework and there are a few hurdles I've come across and gotten past - here are a few tips.

Making your own Controller

The default gateway controller with a fresh install of Kohana is 'welcome'. This means that URIs are written a bit like this:

http://localhost/kohana/welcome/index

But it's not ideal to have 'welcome' in the URI all the time. So, if you want to choose a custom name like 'site', you need to make your own controller...
  1. Copy the welcome controller (welcome.php) in /kohana/applications/controllers/ and paste into the same folder.
  2. Rename the file to site.php
  3. Open the site.php file and change the class declaration to 'class Site_Controller extends Template_Controller'
  4. Now, go to /kohana/system/config/ and copy the file called routes.php to /kohana/application/config/ .
  5. Open up the file and edit like so: $config['_default'] = 'site';
That should do it. Your site will now build its URIs and route through the 'site' controller by default. You should make urls like so:

<?php html::anchor('site/index', 'Home Page'); ?>

Making your own default template

Simply go to /kohana/system/views/kohana/ and copy the template.php file to /kohana/application/views/kohana/. Edit the file as you wish. But, make sure your controller has this line pointing to it: public $template = 'kohana/template';

Making your CSS and Javascript work (get found)

So you make your XHTML template file and are ready to test everything - you stick your CSS in a .css file and your Javascript into a .js file and your images into an 'images' folder and put them in the root (/kohana/). You go to the page through the URI, e.g. http://localhost/kohana/site/index

Huh? What's this? Your CSS, Javascript and image files were not found!

Turns out you need to change the location of your files and add some PHP to your template.
  1. make a folder in root (/kohana/) called 'media'.
  2. make 3 folders called images, css and js inside your media folder and move your images, css and javascript files into their respective folders
  3. Edit your css and js files to point to the right path for the images, e.g: background-image: url(/kohana/media/simages/bg.png); (make sure the first / is there otherwise it won't work
  4. Now edit your template file to include this bit of code in the head section (I called my css file and js file css.css and js.js (imaginative huh?)):
<?php echo html::stylesheet(array('media/css/css'), array('screen')) .
html::script(array('media/js/js'), FALSE); ?>

Now this will put the typical XHTML tags into your page to include outside css and js files:
<link rel="stylesheet" type="text/css" href="/kohana/media/css/css.css" media="screen" />

<script type="text/javascript" src="/kohana/media/js/js.js">