Archive

Posts Tagged ‘JavaScript’

JavaScript: How to prevent execution of JavaScript within a html being added to the DOM

February 5th, 2013 Admin 1 comment

    Getting pieces of html from an external web service, I display them “as is” on a page. To insert the htmls into the document I use handy jQuery methods: append() and html(). The only problem is the htmls contain inclusions of JavaScript that is executed whenever I add the htmls to the DOM (Document Object Model). Having looked for an acceptable solution to prevent untrusted scripts from running I found out that almost all solutions come to removing script-tags from html using the Regular Expressions. I tried a couple of regexes, and they really worked. However, every time I could find such a combination of script-tag, JavaScript inside it and wrapping html when the regexes either didn’t recognize a script block or cut out more than it was needed. And I don’t even mention that parsing an arbitrary HTML with the Regular Expressions is a bad idea in all respects :) . Trying to find another solution, I recalled that if we replace the type=”text/javascript” of a script-tag with the type=”text/xml”, the JavaScript inside will not execute. This is quite known fact, and a few JavaScript libraries use this behavior for their purposes. However, two things impeded me to implement the direct replacing of one type with another: the type=”text/javascript” sub-string may encounter outside the <script>, somewhere in the content (like in this article :) ); the script-tag may be without the type attribute at all, and, in this case, the code inside will be run as if the type=”text/javascript” is specified. Taking into account these conditions, I developed a few tricky regexes, that seemed to be fairly complicated and not reliable enough though. After all, this led me to a thought to examine what happens if the script-tag has two type attributes. Something like this:

<script type="text/xml" type="text/javascript">
    alert('Hello!');
</script>

All browsers I tested this in didn’t execute JavaScript. On the contrary, if I change the type attributes over, the script is executed. Only the first type attribute seems to be efficient. So, my resultant solution is based on the following assumptions:

  • JavaScript inside the <script type=”text/xml”> doesn’t execute;
  • JavaScript inside the <script type=”text/xml” type=”text/javascript”> doesn’t execute as well because only the first type is considered;

So, below is a very simple JavaScript function, which prevents scripts from running and seems to avoid most of drawbacks:

function preventJS(html) {
    return html.replace(/<script(?=(\s|>))/i, '<script type="text/xml" ');
}

The solution still relies on the Regular Expressions, but the regex itself is quite simple and unambiguous. The script-tags are preserved in the html, so you can treat them later in a manner you want.

Below is an example of use

<html>
  <head>
    <title>Prevent scripts from running</title>
    <script src="jquery-1.8.3.js" type="text/javascript"></script>
  </head>
  <body>
    <div id="content"></div>
    <script type="text/javascript">
      $(function () {
        var html1 = "<span>Hello 1<script type='text/javascript'>alert('Hello 1!');<\/script></span>"
        var html2 = "<span>Hello 2 &lt;script&gt; alert('Hi') &lt;/script&gt; <script   type='text/javascript'>alert('Hello 2!');<\/script></span>";
        var html3 = "<script src=\"someJs.js\" type='text/javascript'><\/script>";
        var html4 = "<script>alert('Hello 4!');<\/script>";
        var html5 = "<scriptsomeAttr >alert('Hello 5!');";

        $("#content").html(preventJS(html1));
        $("#content").append(preventJS(html2));
        $("#content").append(preventJS(html3));
        $("#content").append(preventJS(html4));
        $("#content").append(preventJS(html5));
      });

      function preventJS(html) {
        return html.replace(/<script(?=(\s|>))/i, '<script type="text/xml" ');
      }
    </script>
  </body>
</html>

I tested this solution in Google Chrome v. 24.0.1312.56, FireFox v. 18.0.1 and Internet Explorer 9 v.9.0.8112.16421, and it works as directed. However, I still have doubts whether it’s applicable for all browsers and their versions. So, if you have tested it, please don’t hesitate to post a comment here with the result, browser’s name and version you use.

For test purposes you can download a html page and a couple of js-files here. If the preventing works correctly, having opened the page in a browser, you shouldn’t get any alerts.

Related posts:
Categories: JavaScript, jQuery, Regex Tags: , ,

jQuery: Plugins to handle long click and taphold events

December 3rd, 2012 Admin No comments


jQuery plugin to catch a long click event

Below is a simple jQuery plugin to catch a long click or long press:

(function ($) {
  $.fn.longClick = function (callback, timeout) {
   // bind to element's mousedown event to track the longclick's beginning
   $(this).mousedown(function (event) {
    // save the initial event object
    var initialEvent = event;
    // set the delay after which the callback will be called
    var timer = window.setTimeout(function () { callback(initialEvent); }, timeout);
    // bind to global mouseup event for clearance
    $(document).mouseup(function () {
      // clear timer
      window.clearTimeout(timer);
      // unbind from global mouseup event
      $(document).unbind("mouseup");
      return true;
      // use 'return false;' if you need to prevent default handler and
      // stop event bubbling
    });
     return true;
     // use 'return false;' if you need to prevent default handler and
     // stop event bubbling
   });
  };
})(jQuery);

...
// using
(function ($) {
  $("#someDiv").longClick(function (e) {
              alert($(e.target).attr("id") + " was clicked"); },
              1500);
})(jQuery);

The plugin accepts a callback function that will be called once a long click event occurred and a timeout in milliseconds saying how long user should keep button pressed to produce the long click.


jQuery plugin to catch a taphold event

The same long click for iPad is usually called taphold and can be implemented as follows:

(function ($) {
  $.fn.taphold = function (callback, timeout) {
   // bind to element's touchstart event to track the taphold's beginning
   $(this).bind("touchstart", function (event) {
    // save the initial event object
    var initialEvent = event;
    // set the delay after which the callback will be called
    var timer = window.setTimeout(function () { callback(initialEvent); }, timeout);
    // bind to global touchend and touchcancel events for clearance
    $(document).bind("touchend touchcancel", function () {
      // clear timer
      window.clearTimeout(timer);
      // unbind from touchend and touchcancel events
      $(document).unbind("touchend touchcancel");
      return true;
      // use 'return false;' if you need to prevent default handler and
      // stop event bubbling
    });
    return true;
    // use 'return false;' if you need to prevent default handler and
    // stop event bubbling
   });
  };
})(jQuery);

...
// using
(function ($) {
  $("#someDiv").taphold(function () {
               alert($(e.target).attr("id") + " was tapholded"); },
               1500);
})(jQuery);

The only difference from the previous plugin is that touchable device’s events are used.


Combined jQuery plugin to catch both long click and taphold events

Two shown above plugins can be quite easily combined in one. The new plugin checks if the current device is an iPad and, if so, deals with such iPad events as touchstart, touchend and touchcancel; otherwise, it uses traditional mousedown and mouseup.

(function ($) {
 $.fn.longclick = function (callback, timeout) {
   var isIPad = $.isIPad();

   var startEvents = isIPad ? "touchstart" :           "mousedown";
   var endEvents   = isIPad ? "touchend touchcancel" : "mouseup";

   $(this).bind(startEvents, function (event) {
    // save the initial event object
    var initialEvent = event;
    // set delay after which the callback will be called
    var timer = window.setTimeout(function () { callback(initialEvent); }, timeout);
    // bind to global event(s) for clearance
    $(document).bind(endEvents, function () {
        // clear timer
        window.clearTimeout(timer);
        // reset global event handlers
        $(document).unbind(endEvents);
        return true;
        // use 'return false;' if you need to prevent default handler and
        // stop event bubbling
    });
    return true;
    // use 'return false;' if you need to prevent default handler and
    // stop event bubbling
   });
 };
})(jQuery);

...
// using
(function ($) {
    $("#someDiv").longclick(function () {
             alert($(e.target).attr("id") + " was clicked"); },
             1500);
})(jQuery);

Note that the isIPad plugin was described in the post – jQuery: Plugins to detect iPad and iPhone devices.

Related posts:
Categories: iPad, JavaScript, jQuery Tags: , ,

jQuery: Plugins to detect iPad and iPhone devices

November 30th, 2012 Admin No comments


jQuery plugin for iPad detection

Below is a simple jQuery plugin to detect whether a page is opened in an iPad:

(function ($) {
    $.isIPad = function () {
        return (typeof navigator != "undefined" &&
               navigator && navigator.userAgent &&
               navigator.userAgent.match(/iPad/i) != null);
    };
})(jQuery);

...
// using
$(function(){
    if($.isIPad())
        alert('Hello, iPad');
});


jQuery plugin for iPhone detection

The next plugin allows to detect an iPhone:

(function ($) {
    $.isIPhone = function () {
        if(!$.isIPad())
            return (typeof navigator != "undefined" &&
               navigator && navigator.userAgent &&
               (navigator.userAgent.match(/iPhone/i) != null ||
                navigator.userAgent.match(/iPod/i) != null));
        return false;
    };
})(jQuery);

...
// using
$(function(){
    if($.isIPhone())
        alert('Hello, iPhone');
});

Note, initially I check if the device is an iPad and only then try to identify it as an iPhone. I do so because people reports that some iPad browsers/applications use substring ‘iPhone’ in their userAgents along with the expected ‘iPad’. For example, such behavior was noticed in Facebook UIWebView.


jQuery plugin for Apple mobile device detection

To detect any Apple mobile devices (iPad, iPhone or iPod) you can use the following jQuery plugin:

(function ($) {
    $.isAppleMobile = function () {
        return (typeof navigator != "undefined" &&
               navigator && navigator.userAgent &&
               navigator.userAgent.match(/(iPad|iPhone|iPod)/i) != null);
    };
})(jQuery);

...
// using
$(function(){
    if($.isAppleMobile())
        alert('Hello, Apple device');
});
Related posts:

JavaScript: How to determine whether a variable has a valid value

November 29th, 2012 Admin No comments

    A good way to examine whether a variable (or object’s field) has a valid value looks like the following:

if( variable /* obj.field */ ) {
}

This statement allows to check if the value is null (explicit assignment of null to variable happened) or undefined (variable wasn’t initialized). To be more precise it returns true when the variable is not

  • null
  • undefined
  • NaN
  • empty string (“”)
  • 0
  • false

Mostly, such validity check is more than enough for further safe treating with the variable. However, we’ll get the “‘variable’ is undefined error” if the variable is undeclared. In this case we have to perform the following check in advance:

if(typeof variable !== 'undefined') {
}

Of course, if you are pretty sure that the variable exists (is declared), you can omit the typeof check. But if you deal with something going from an external library or source, I recommend having it. So, gathering all together, we obtain the following code:

if(typeof variable !== 'undefined' && variable) {
}

In some forums, people from time to time suggest to wrap such check into a function. Let’s assume we have such function:

function isValid(obj) {
  return typeof obj !== 'undefined' && obj;
}

However, it doesn’t make sense at all as you can’t call the function, passing an undeclared variable, in any case. The mentioned above error is thrown whenever you try addressing to the unknown variable:

if(isValid(varibale)) // throw "'variable' is undefined error",
                      // if the variable doesn't exist
  ...

Thus, in case of undeclared variable, we have to have inline typeof check. In all other cases, it’s enough to have simple if(variable). So, using variables and objects likely declared outside of my code, I examine them like in the sample below:

if(typeof navigator != "undefined" && navigator && navigator.userAgent)
     alert(navigator.userAgent);
Categories: JavaScript, jQuery Tags: ,

jQuery: IsNullOrEmpty plugin for jQuery

November 20th, 2012 Admin No comments

    I was a bit disappointed when couldn’t find in jQuery library a method similar to String.IsNullOrEmpty from C#. So, below is a simple jQuery plugin to examine whether the passed string is empty or null.

(function ($) {
    $.isNullOrEmpty = function (str) {
        return !str || $.trim(str) === ""; // the trim method is provided by jQuery
    };
})(jQuery);

Some samples of use

var res = $.isNullOrEmpty(''); // true
res = $.isNullOrEmpty("bla-bla-bla"); // false
res = $.isNullOrEmpty(null); // true
res = $.isNullOrEmpty(); // true
Related posts:
Categories: JavaScript, jQuery Tags: ,