Loading blog entries.. loading


Blogs which referenced tag: [Javascript]

 

Resolving mouseover/mouseout multi-trigger problem
 
1211 Views 0 Comments
Written by Wayne Ye  Friday, December 23, 2011Category:Programming»Web Development»JavaScript 

Background

While I was developing my blog's comments function, I hope reader can write down their Gravatar email address, and my preferable UI was an "hint icon" dispolayed desides the Email textbox, so that while reader mouse overs it an overlay box will show the reason why Email is required, in additional, I want to add a little bit fancier animation:

  • When user's mouse hovers on the icon, show the div box from small to large, once reaches predefined size, fades in the hint sentente.
  • When mouse out the icon, fades out the hint sentence and then hides the div from large to small.

My requirement seems easy, however, I did spend two whole days in making it perfect, so I write down my investigation path here. 

The problems I faced

My first thoughts was definitely simple, subscribe the onmouseover/onmouseout event for the hint icon, and setinterval the size animation, once finished, fades in the texts.

That's fine! But I soon encountered one problem which is easy to trigger: mouse keeps on overing/outing the icon quickly (as long as the interval is shorter than the sizing animation), it will cause the two event handlers (mouseover/mouseout) multi-triggered so that a infinite loop could be easily caused.

The multi-trigger problem I faced is not the one related with DOM event bubbling, which is well described in jQuery mouseover API.

Majority functions on my simple blog didn't use any third party JS library including jQuery, instead, I was trying to be a "rambo", just for improving my coding skills - by implementing various kinds of features and resolving various kinds of problems.

Overcoming this issue cost me one whole day:) I tried strategies listed below:

  1. Put global variables indicating the showing/hiding process - isShowing & isHiding.
  2. Clearing oppositeinterval handle as soon as over/out event was triggered.
  3. Inspired by #2, unsubscribing oppotite event handler as soon as mouseover/mouseout was captured.

#1 does not solve the problem, I tried while multi-triggered, the interval cannot be cleared (not very sure the reason), #2 absolutely not work because it will stop unfinished animation. Finally I resolved the problem using #3, which I think it is the best one. 

Implementation

The HTML

 <div id="hintContainer">
    <div id="hintIcon">
        <img src="../Images/Hint.gif" alt="Email Hint">
    </div>
    <div id="CommentHint">
        <div id="hintText">
            Required (not shown), used only for displaying <strong>Gravatar</strong> and receiving
            future notification when new comment(s) posted on this blog.
        </div>
    </div>
</div>

The CSS

 <style type="text/css">
    #hintContainer
    {
        width: 184px;
        height: 80px;
    }
    #hintIcon
    {
        width: 16px;
        height: 16px;
        float: left;
        cursor: pointer;
    }
    #CommentHint
    {
        position:absolute;
        color: #fff;
        width: 0;
        height: 0;
        background-color: black; /*#adc7ed*/
        border: 1px dotted #666;
        padding: 2px;
        display: none;
    }
    #hintText
    {
        opacity: 0;
        filter: Alpha(opacity=0);
    }
</style>

The JavaScript

Foundation methods in my "rambo" library:

 var $id = function (id) { return document.getElementById(id); }
function bindEvent(domObj, eventName, evtHandler, useCapture) {
    if (domObj.addEventListener) {
        domObj.addEventListener(eventName, evtHandler, useCapture ? useCapture : false);
    }
    else if (domObj.attachEvent) { // IE 8 and below
        evtHandler.wrapper = function () {
            evtHandler.call(domObj)
        };

        domObj.attachEvent("on" + eventName, evtHandler.wrapper);
    }
}
function setSize(ele, width, height) {
    ele.style.width = width + 'px';
    ele.style.height = height + 'px';
}
function setPosition(ele, left, top) {
    ele.style.left = left + 'px';
    ele.style.top = top + 'px';
}

Animation methods:

 var hintIcon = $id('hintIcon'), commentHint = $id('CommentHint'), hintText = $id('hintText');
bindEvent(hintIcon, "mouseover", showHint);

var totalFrames = 20, curFrame = 0;
var sliceWidth = 180 / totalFrames, sliceHeight = 80 / totalFrames;
var showHinthandler = hideHinthandler = undefined;
var offset = 10;

function showHint(evt) {
    if (!evt)
        evt = window.event;

    // Unbind mouseover immediately to prevent multi-trigger
    unbindEvent(this, "mouseover", showHint);

    setPosition(commentHint, evt.clientX + offset, evt.clientY);
           
    showElement(commentHint);
    showElement(hintText);

    showHinthandler = setInterval(function () {
        //console.log("show: " + curFrame);

        if (++curFrame <= totalFrames)
            setSize(commentHint, sliceWidth * curFrame, sliceHeight * curFrame);
        else {
            clearInterval(showHinthandler);
            curFrame = totalFrames;

            // Fade in hint text
            divFadeIn(hintText, 2, 10);

            // Bind mouseout event back to the icon UNTIL finished showing
            bindEvent(hintIcon, "mouseout", hideHint);
        }
    }, 10);
}
function hideHint(evt) {
    if (!evt)
        evt = window.event;

    // Unbind mouseover immediately to prevent multi-trigger
    unbindEvent(this, "mouseout", hideHint);

    divFadeOut(hintText, 2, 10);

    setTimeout(function () {
        hideHinthandler = setInterval(function () {

            hideElement(hintText);
            console.log("hide: " + curFrame);


            if (--curFrame >= 0) {
                setSize(commentHint, sliceWidth * curFrame, sliceHeight * curFrame);
            }
            else {
                clearInterval(hideHinthandler);
                curFrame = 0;

                hideElement(commentHint);

                // Bind mouseover event back to the icon UNTIL finished hiding
                bindEvent(hintIcon, "mouseover", showHint);
            }
        }, 10);
    }, 800);
}

Conclusion

I guess this is a pretty good problem for interview, I am fool so I cannot resolve it in short period, however, I think good fronteers should solve it greatly:)


View Post»



Permalink:http://wayneye.com/Blog/Resolving-mouseover-mouseout-Multi-Trigger-Problem
Tag:

HTML5 WebMessaging In Essence
 
1863 Views 0 Comments
Written by Wayne Ye  Tuesday, August 30, 2011Category:Programming»Web Development»JavaScript 

Download HTML5_Cross-Domain_WebMessaging_Demo.zip - 2.97 KB

As a web developer, sometimes we are easy to encounter one problem: Cross-Domain communication, conforming Same-Origin-Policy, JavaScript code cannot access code stay in different domain(or sub-domain) or protocol (HTTP/HTTPs) or port, so there was no direct (or I can say: simple) way to achieve Cross-Domain Communication. However, those kinds of requirements does happen: page A and page B are in different domain,  B is "embedded" in A, i.e., there is an "iframe" in page A whose "src" is page B's URL, now page A wants to control page B and vise-versa. 

By limiting the solution to be done by 100% client JavaScript, beforehand HTML5, there are a number of tricky "hacks", such as:

  1. URL long polling: container page A changes the iframe page B's URL hash, and B periodically checks the hash, once the hash changed, it takes action according to the contracted hash value. [BTW, the pattern can be revised to be non-polling by HTML5 onchashchange event]
  2. CrossFrame, a Safe Communication Mechanism Across Documents and Across Domains.
  3. Window Size Monitoring: update the iframe's window size once, and the containning window subscribes its "onresize" event then takes corresponding action(s). Google Mapplets adopted this pattern.

Well, personally I really don't like all of them... either inelegant, or violates the original functionalities of DOM elements, or too complecated. I believe many people don't like them too even the pattern inventors I bet... That why WHATWG created Cross-Domain communication in HTML5: Web Messaging.

As an HTML5 crazy advocator I like it very much, complete client communication, no server impact, efficient, secure (at least in theory).

How to

"Child" can be an iframe or an popup window by invocking window.open, "parent page" A contains source code is like below:

 <iframe id="ifr" src="http://domainB.com/B.htm" onload="sendCommand();">
  No frame!
</iframe>

<script type="text/javascript">  
  function sendCommand() {
    var ifr = document.getElementById("ifr");
    ifr.contentWindow.postMessage("Hello", "http://domainB.com");
  }
</script>

Notice, make sure post message only when the iframe is loaded, otherwise the contentWindow will be still in same domain with the container page.

Child page B contains code like below:

 <input type="button" value="Cross domain call" onclick="sendMsg();" />

<script>
window.addEventListener("message", receiveMessage, false);

function receiveMessage(evt) {
    console.log("Page B received message from origin: %s.", evt.origin);
    console.log("Event data: %s", evt.data);
    //evt.source will be a window who sent the message, it can be used to post message to it
   
    // Take action(s)
}
</script>

The demo code above is one direction: parent sends message to child (iframe), actually bi-directional message trasfer can also be done, similar with "Parent control child", child page posts message to container window, only different is call "parent.postMessage".

 function receiveMessage(evt) {
    evt.source.postmessage("Hello caller");
    // or parent.postmessage("Hello parent");
}

Web Messaging Essential

In a nutshell, HTML5 Web Messaging is a suite of JavaScript API exposed by web browser, to communicate between different browsing context, when JavaScript code in one browser tab/window trys to deliver a message to another tab/window, web browser locates the target tab/window under the specified domain, and file a MessageEvent (which inherits from DOMEvent) to the target tab/window, so if the target tab/window already subscribed the message event, it will gets notified, eventually the message got delivered through MessageEvent.data.

Live Demo

I've done a demo in my dev machine, I override my local hosts file to let  Container.com, DomainA.com, DomainB.com and DomainC.com all point to 127.0.0.1:

127.0.1.1 Container.com
127.0.0.1 DomainA.com

127.0.0.1 DomainB.com
127.0.0.1 DomainC.com

I prepared a Container page which contains code below:

 <h3>HTML5 Cross-Domain post message demo</h3>
<p id="infoBar"></p>
<div id="wrapperA">
    <input type="text" id="txtA" /><br />
    <input type="button" value="Post Message" onclick="postMsgToIfr('A');" />
    <br />
    <iframe id="ifrA" src="http://DomainA.com/A.htm"></iframe>
</div>
<div id="wrapperB">
    <input type="text" id="txtB" /><br />
    <input type="button" value="Post Message" onclick="postMsgToIfr('B');" />
    <br />
    <iframe id="ifrB" src="http://DomainB.com/B.htm"></iframe>
</div>
<div id="wrapperC">
    <input type="text" id="txtC" /><br />
    <input type="button" value="Post Message" onclick="postMsgToIfr('C');" />
    <br />
    <iframe id="ifrC" src="http://DomainC.com/C.htm"></iframe>
</div>
<div style="clear: both">
</div>
<script type="text/javascript">
    window.addEventListener("message", receiveMessage, false);

    var infoBar = document.getElementById("infoBar");
    function receiveMessage(evt) {
        infoBar.innerHTML += evt.origin + ": " + evt.data + "<br />";
    }

    function postMsgToIfr(domain) {
        switch (domain) {
            case "A":
                var ifr = document.getElementById("ifrA");
                ifr.contentWindow.postMessage(document.getElementById("txtA").value, "http://DomainA.com");
                break;
            case "B":
                var ifr = document.getElementById("ifrB");
                ifr.contentWindow.postMessage(document.getElementById("txtB").value, "http://DomainB.com");
                break;
            case "C":
                var ifr = document.getElementById("ifrC");
                ifr.contentWindow.postMessage(document.getElementById("txtC").value, "http://DomainC.com");
                break;
            default:
                throw new error("No such domain!");
        }
    }       
</script>

And three pages: A.htm located in DomainA.com, B.htm located in DomainB.com, C.htm located in DomainC.com, phisically they all located under C:\inetpub\wwwrooot, while in the browser I manually type DomainA/B/C.com to make the cheatSmile, the code in the A/B/C page are similar, showing below:

 <h4>DomainA/A.htm1</h4>
<input type="button" value="Cross domain call" onclick="doClick();" />
<div id="d">
</div>
<script>
    window.addEventListener("message", receiveMessage, false);

    function doClick() {
        parent.postMessage("Message sent from " + location.host, "http://container.com");
    }

    var d = document.getElementById("d");
    function receiveMessage(evt) {
        d.innerHTML += "Received message \"<span style=\"color:red\">" + evt.data + "</span>\" from domain: " + evt.origin + "<br />";
    }
</script>

I recorded a gif image below to demonstrate the Cross-Domain messaging:

HTML5 Cross-Domain Messaging Demo

See the message passed through different domain in bi-direction? Isn't it cool?

MessageChannel

To support independent communication under different browsing context, HTML5 introduced Message Channel to post message independently, its official definition is showing below:

Communication channels in this mechanisms are implemented as two-ways pipes, with a port at each end. Messages sent in one port are delivered at the other port, and vice-versa. Messages are asynchronous, and delivered as DOM events. 

I spent about half a day in investigating the Message Channel and finally got it worked, my code is showing below:

Container page source code

 <iframe id="ifr" src="http://wayneye.me/WebProjects/HRMS/Opener.html" onload="initMessaging()"></iframe>
<input type="button" value="Post Message" onclick="postMsg();" />
<div id="d"></div>
<script>
var d = document.getElementById("d");
var channel = new MessageChannel();
channel.port1.onmessage = function (evt) {
    d.innerHTML += evt.origin + ": " + evt.data + "<br />";
};

function initMessaging() {
    var child = document.getElementById("ifr");
    child.contentWindow.postMessage('hello', 'http://wayneye.me', [channel.port2]);
}

function postMsg() {
    channel.port1.postMessage('Message sent from ' + location.host);
}
</script>

iframe page source code

 <div id="info"></div>
<input type="button" value="Post Message" onclick="postMsg();" />
<script>
var info = document.getElementById("info");
var port = null;
window.addEventListener("message", function (e) {
console.log(e);
    if(e.ports && e.ports.length > 0) {
        port = e.ports[0];
        port.start();
        port.addEventListener("message", function (evt) {
            info.innerHTML += "Received message \"" + evt.data + "\" from domain: " + evt.origin + "<br />";
        }, false);
    }
}, false);

function postMsg() {
    if(port) {
        port.postMessage("Data sent from " + location.host);
    }
}
</script>

The entire process can be described as:

  1. Container page (A) embedded an iframe whose src is pointing to a page (B) in different domain.
  2. Once the iframe loaded, the container posts a message to page B with a MessagePortArray.  
  3. Page B received the message as well as the array containing a list of MessagePort objects.
  4. Page B registers onmessage event on port instance.
  5. Page B invokes port.postmessage to send a message to page A through this MessageChannel. 
At this timestamp, I seems only Opera correctly supports MessageChannel, Google Chrome and IE10 Platform Preview 2 failed to deliver the ports array, Safari cannot gets the onmessage event fired. Firefox 7.0 beta event doesn't support MessageChannel object.
Note: Ports can also enable communication between HTML5 Web Workers.

One more thing (plagiarize Steve JobsSmile), to use Message Channel one noticable point is, web developer should explicitly close the channel once there is no need, otherwise there will be a strong reference between two pages, as W3 official page emphasized below:

Authors are strongly encouraged to explicitly close MessagePort objects to disentangle them, so that their resources can be recollected. Creating many MessagePort objects and discarding them without closing them can lead to high memory usage.

Further reading

HTML5 Web Messaging

window.postMessage - MDN Docs

HTML5 Demo: postMessage (cross domain)

HTML5′s window.postMessage AP

Internet Explorer 10 Platform Preview: HTML5

http://ithelp.ithome.com.tw/question/10057709

 

Also posted on CodeProject: http://www.codeproject.com/KB/HTML/HTML5-WebMessaging.aspx


View Post»



Permalink:http://wayneye.com/Blog/HTML5-WebMessaging-In-Essence
Tag:

nodejs+express+jade+socket.io on Ubuntu 11.04
 
7571 Views 1 Comments
Written by Wayne Ye  Monday, August 29, 2011Category:Programming»Web Development»nodejs 

Introduction

socket.io is a brilliant project which perfectly supports HTML5 WebSocket, in additional, it can fall back to flash or long polling when the client web browser does not support WebSocket, I explored it today on Ubuntu, I summarized the process in this post.

 

Install nodejs

I used nodejs v0.4.11, the latest stable version, by mannually compile/make/install.

sudo curl http://nodejs.org/dist/node-v0.4.11.tar.gz -o ~/Desktop/WayneDevLab/node.tar

sudo tar -xf node.tar cd node-v0.4.11

./configure

make

sudo make install

In the "./configure" step above if it prompted "libssl-dev" not found, please install libssl-dev (sudo apt-get install libssl-dev) which is required by node for hosting HTTPs server.

Install npm

curl http://npmjs.org/install.sh | sh

Install express

express is an insanely fast and high performance server-side JavaScript web development framework built on node, hosting a real web server based on node will be much harder without it:)

$ npm install -g express
$ express /tmp/foo && cd /tmp/foo
$ npm install -d 

Install socket.io

npm install socket.io

Setting up the Web server!!

I've modified my app.js as below:

 var express = require('express');

var app = module.exports = express.createServer(),
    io = require('socket.io').listen(app);

// Configuration
app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.set('view options', {layout: false});
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

app.get('/', function(req, res){
  res.render('index', {
      title: 'Wayne Express Hello World',
      youAreUsingJade: true,
      domain: '192.168.1.4'
  });
});

app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);

io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

And below is my index.jade:

!!! 5
html(lang="en")
  head
    title= title
    script(src='http://'+ domain + ':3000/socket.io/socket.io.js')
    script(type='text/javascript')
      var socket;
      socket =  io.connect('http://192.168.1.4:3000');

      socket.on('news', function (data) {
       console.log(data);
       socket.emit('my other event', { my: 'data' });
             });
  body
    h1 Wayne WebSocket Demo using Socket.io
    #container
      - if (youAreUsingJade)
        p You are amazing
      - else
        p Get on it!

    p Powered By a(href='http://socket.io') Socket.io

    footer Copyright©2011 http://wayneye.com

Testing everything up

Start the server by:

$ node app.js

It works:)

I tested the combination above by using google Chromoum Dev 12 and Dev 15, they seperately adhere WebSocket protocol draft-hixie-thewebsocketprotocol-76 and draft-ietf-hybi-thewebsocketprotocol-10, the connection details for hybi10 is showing below:

socket.io

socket.io will print out useful information on console when running:

socket.io console

 

Wish that helps:)


View Post»



Permalink:http://wayneye.com/Blog/nodejs-express-jade-socketio-On-Ubuntu
Tag:

HTML5 WebSocket in Essence技术分享
 
856 Views 0 Comments
Written by Wayne Ye  Saturday, August 20, 2011Category:Programming»Web Development»HTML/CSS 

今天下午,我非常荣幸受邀参加HTML5兴趣小组每月一次的沙龙活动,我给大家分享了HTML5 WebSocket的特性,协议本质,以及我的Team Poker demo。

第一次做技术分享,表面“淡定“,内心紧张,因语速较快原本打算持续1个小时左右的分享,大约40分钟就结束了,囧Smile

现场照片

现场照片

在谈各种comet技巧

Wayne

PPT

HTML5 WebSocket in Essence on Prezi

现场视频

摄影帅哥貌似对焦不实的说Smile

下一次,希望更好!+U!


View Post»



Permalink:http://wayneye.com/Blog/HTML5-WebSocket-In-Essence-Public-Speak
Tag:

JavaScript - Foundation of the Language
 
1018 Views 0 Comments
Written by Wayne Ye  Sunday, July 24, 2011Category:Programming»Web Development»JavaScript 

Introduction

JavaScript "was born under the shadow of Java" - Brenden Eich, it is "the most misunderstood programming language in the world" - Douglas Crockford. JavaScript was used so widely nowadays, nearly everywhere as long as you are using a web browser and surfing the internet, most of the websites have JS inside, and even server side - nodejs, according to http://langpop.com/, JavaScript is the fourth popular programming language in the world

In this post I am trying to use refined language to cover some foundation of JavaScript (many of which confused quite a number of developers) including basic data types, comparison mechanism, functions, Execution context, Variable Scope Chain, essence of Closure and anounymous function (lambda). Hope it can more or less help people have more fun and less frustration in the future JS coding. 

Basic data types/object types 

In JavaScript, there are 5 basic types: Undefined, Null, Boolean, Number and String, integers  Boolean values and strings are accessed by value, that's different with many modern languages like C# (System.String) or Python (PyStringObject), string are object and passed by reference, JS code snipppet below proves that string is stored in the stack and passed by value. 

var str = "a";
                
function strValTest(s) {
    s = "b";  // "s" is a String value: "a".
    alert(s); // Will alert "b".
}
strValTest(str);
alert(str); // Will alert "a", because when called strValTest, String variable's value is passed as argument.

String is JavaScript is also immutable just like many other languages, i.e. any change applied on an existing string will create a new string in memory and destroy the old one (there is still different with C# in which there is a String Intern Pool to store all String values in managed heap). Code snippet below shows the difference between string and String: 

var str1 = "A new String";
console.log("str1");
console.log(str1 instanceof String); // false
console.log(str1 instanceof Object); // false
console.log(typeof (str1)); // string

var str2 = new String("A new String");  // Create a new Object stored on the heap with value "A new String"
console.log("str2");
console.log(str2 instanceof String); // true
console.log(str2 instanceof Object); // true
console.log(typeof (str2)); // object

Then you might have question of: how come string instance has methods now that string is value type? The answer is that In JavaScript there are corresponding Object wrapper for the basic types: Number, Boolean and String, they inherit from Object and have their own properties and methods such as Number.toFixed() and String.indexOf(), simple code snippet below:

string str = "I am a JSer"; // Create a new string variable on the stack with value "I am a JSer".
alert(str.indexOf("JSer"));

Essentially at the back end, JS interpreter will temporarily creates a new String object and invokes its instance method "indexOf", after the method call finished, the temporary String object will be claimed, the process can be demonstrated as below:

string str = "I am a JSer";
var tmp = new String(str);
alert(tmp.indexOf("JSer"));
tmp = null;

 

Comparison

Comparison might be a very confused part in JavaScript, why? See code below:

console.log(null == undefined); // true Per ECMA-262, null and undefined are superficially equal, essentially "the value undefined is a derivative of null"<professional>.
console.log(null === undefined); // false
console.log(NaN == NaN);  // false. A specific NaN is not considered equal to another NaN because they may be different values. Also refer: http://en.wikipedia.org/wiki/NaN
console.log('5' == 5);   // true. 
console.log('5' === 5);   // false. typeof('5') is string and typeof(5) is number
console.log(false == 0);  // true
console.log(true == 1);  // true
console.log(null == 0);  // false

console.log(typeof (null)); // object
console.log(typeof (undefined)); // undefined

Foo.prototype = {
	constructor: Foo,
	valueOf: function () {
		return "Object Foo";
	},
	toString: function () {
		return "Foo";
	}
};

var foo1 = new Foo();
console.log("foo1 == foo2: " + (foo1 == "Object Foo")); // true will call foo1.valueOf() 

var foo2 = new Foo();
console.log("foo1 == foo2: " + (foo1 == foo2)); // false foo1, foo2 point to diffrent instance of Foo

foo2 = foo1;
console.log("foo1 == foo2: " + (foo1 == foo2)); // true no doudt
</professional>

Are you sweating? I did... So I read book and copied Paragraph below from <Professional JavaScript for Web Developers>. 

 

  • If an operand is a Boolean value, convert it into a numeric value before checking for equality. 
  • A value of false converts to 0, whereas a value of true converts to 1. 
  • If one operand is a string and the other is a number, attempt to convert the string into a number before checking for equality. 
  • If either operand is an object, the valueOf() method is called to retrieve a primitive value to compare according to the previous rules. If valueOf() is not available, then toString() is called. 
  • The operators also follow these rules when making comparisons:
  • Values of null and undefined are equal. 
  • Values of null and undefined cannot be converted into any other values for equality checking. 
  • If either operand is NaN, the equal operator returns false and the not - equal operator returns true. Important note: Even if both operands are NaN , the equal operator returns false because, by rule, NaN is not equal to NaN. 
  • If both operands are objects, then they are compared to see if they are the same object. If both operands point to the same object, then the equal operator returns true . Otherwise, the two are not equal.  

Function

In JavaScript, function is not only traditional function but also an object, define a function is actually define a pointer to that function, and function is not only traditional function but also an  Object. I wrote code snippet below for better understanding: 

function dummyFunc() { // Define a function and a pointer to it, the pointer's name is "dummyFunc"
	this.DummyProperty = "Dummy Property";
	console.log("Dummy func");
}

var tempFunc = dummyFunc; // Define a variable tempFunc, let it equal to dummyFunc which is a function pointer pointing to function defined above
dummyFunc = null; // null the dummyFunc
tempFunc(); // tempFunc still points to the function defined above so still can be executed.

var dummy = new tempFunc(); // Will invoke tempFunc's constructor to form a new Object
console.log(dummy.DummyProperty);

Another very important point of functions is the parameters, in JavaScript, function's arguments are ALL passed by value, NOT reference even if the argument is an Object, to prove this please see code snippet below:

var person = new Object();
function setName(obj) {
	obj.Name = "Wayne"; // obj is actually newly created and given the pointer's value, so obj and the reference type outside this function will both point to the Object on the heap, thus operation on obj will affect the Object passed in the function.
	
	obj = new Object(); // By executing this line, temporary variable obj will point to a new Object, has no relationship with the passed-in Object any more.
	obj.Name = "Wendy";
}

setName(person); // Executing this line will pass person's pointer stored in stack to the function setName, 
alert(person.Name); // Will alert "Wayne"

Execution Context and Variable Scope Chain 


View Post»



Permalink:http://wayneye.com/Blog/JavaScript-Foundation-Of-The-Language
Tag:

HTML5 Web Socket in Essence
 
2403 Views 1 Comments
Written by Wayne Ye  Friday, June 10, 2011Category:Programming»Web Development»HTML/CSS 

HTML5 WebSocket defines a bi-directional, full-duplex communication channel operates through a single TCP connection, this article discusses its fantastic performance, the WebSocket protocol principle and its handshake mechanism, and develop a WebSocket application in action (Team Poker).


Embeded youku video link because Youtube is outside of the largest "intranet" in the entire universe!!

Table of Content

  1. Introduction
  2. Background
  3. WebSocket In Essence
  4. Experimental Demos
  5. Browser Support
  6. WebSocket JavaScript API
  7. Develop WebSocket In Action - Team Poker
  8. Open Issues
  9. Conclusion
  10. References & Resources 

Introduction

HTML5 WebSocket defines a bi-directional, full-duplex communication channel that operates through a single TCP socket over the Web, it provides efficient, low-latency and low cost connection between web client and server, based on WebSocket, developers can build scalablereal-time web applications in the future. Section below is the official definition of WebSocket copied from IETF WebSocket protocol page: 

The WebSocket protocol enables two-way communication between a user agent running untrusted code running in a controlled environment to a remote host that has opted-in to communications from that code.  The security model used for this is the Origin-based security model commonly used by Web browsers.  The protocol consists of an initial handshake followed by basic message framing, layered over TCP.  The goal of this technology is to provide a mechanism for browser-based applications that need two-way communication with servers that does not rely on opening multiple HTTP connections (e.g. using XMLHttpRequest or <iframe>s and long polling).

This article is trying to go through WebSocket basic concept, the problems it is going to solve, explain it in essence, watch some experimental Demos, develop a simple WebSocket application in action (Team Poker), and describe current open issues of WebSocket. I sincerely hope it will be systematicallyeasy to understandfrom surface to deep so that eventually readers would not only learn what WebSocket is from high level but also understand it in depth! Any thoughts, suggestions or criticism you may have after reading this article will help me to improve in the future, i would appreciate it if you could leave a comment.

Background

In traditional web applications, in order to achieve some real-time interaction with server, developers had to employ several tricky ways such as Ajax pollingComet (A.K.A Ajax push, Full Duplex Ajax, HTTP Streaming, etc.), those technologies either periodically fire HTTP requests to server or hold the HTTP connection with server for a long time, which "contain lots of additional, unnecessary header data and introduce latency" and resulted in "an outrageously high price tag". websocket.org explained the problems exhaustively, compared the performance of Ajax polling and WebSocket in detail, built up two simple web pages, one periodically communicated with server using traditional HTTP and the other used HTML5 WebSocket, in the testing each HTTP request/response header is approximate 871 byte, while data length of WebSocket connection is much shorter: 2 bytes after connection established, as the transfer count getting larger, the result will be:

Traditional HTTP Request 

  • Use case A: 1,000 clients polling every second: Network throughput is (871 x 1,000) = 871,000 bytes = 6,968,000 bits per second (6.6 Mbps)

  • Use case B: 10,000 clients polling every second: Network throughput is (871 x 10,000) = 8,710,000 bytes = 69,680,000 bits per second (66 Mbps)

  • Use case C: 100,000 clients polling every 1 second: Network throughput is (871 x 100,000) = 87,100,000 bytes = 696,800,000 bits per second (665 Mbps)

HTML5 WebSocket

  • Use case A: 1,000 clients receive 1 message per second: Network throughput is (2 x 1,000) = 2,000 bytes = 16,000 bits per second (0.015 Mbps)

  • Use case B: 10,000 clients receive 1 message per second: Network throughput is (2 x 10,000) = 20,000 bytes = 160,000 bits per second (0.153 Kbps)

  • Use case C: 100,000 clients receive 1 message per second: Network throughput is (2 x 100,000) = 200,000 bytes = 1,600,000 bits per second (1.526 Kbps)

Finally a more readable diagram:

Polling VS WebSocket

 "HTML5 Web Sockets can provide a 500:1 or — depending on the size of the HTTP headers — even a 1000:1 reduction in unnecessary HTTP header traffic and 3:1 reduction in latency".  --WebSocket.org

WebSocket In Essence

The motivation of creating WebSocket is to replace polling and long polling(Comet), and endow HTML5 web application the ability of real-time communication. Browser based web application can fire WebSocket connection request through JavaScript API, and then transfer data with server over only one TCP connection.


View Post»



Permalink:http://wayneye.com/Blog/HTML5-Web-Socket-In-Essence
Tag:

AJAX Cross-Origin HTTP request
 
3589 Views 3 Comments
Written by Wayne Ye  Friday, April 1, 2011Category:Programming»Web Development»HTTP/REST 

Background

Cross-Origin Request Sharing - CORS (A.K.A. Cross-Domain AJAX request) is an issue that most web developers might encounter, according to Same-Origin-Policy, browsers restrict client JavaScript in a security sandbox, usually JS cannot directly communicate with a remote server from a different domain. In the past developers created many tricky ways to achieve Cross-Domain resource request, most commonly using ways are:

  1. Use Flash/Silverlight or server side as a "proxy" to communicate with remote.
  2. JSON With Padding (JSONP).
  3. Embeds remote server in an iframe and communicate through fragment or window.name, refer here.

And so on..

Those tricky ways have more or less some issues, for example JSONP might result in security hole if developers simply "eval" it, and #3 above, although it works, both domains should build strict contract between each other, it neither flexible nor elegant IMHO:)

W3C had introduced Cross-Origin Resource Sharing (CORS) as a standard solution to provide a safe, flexible and a recommended standard way to solve this issue. 

Mechanism

From a high level we can simply deem CORS is a contract between client AJAX call from domain A and a page hosted on domain B, a tipical Cross-Origin request/response would be:

DomainA AJAX request headers

Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com 

DomainB response headers

Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive

The blue parts I marked above were the kernal facts, "Origin" request header "indicates where the cross-origin request or preflight request originates from", the "Access-Control-Allow-Origin" response header indicates this page allows remote request from DomainA (if the value is * indicate allows remote requests from any domain).


View Post»



Permalink:http://wayneye.com/Blog/Ajax-Cross-Origin-HTTP-request
Tag:

HTML5 Web Storage in Essence
 
2547 Views 5 Comments
Written by Wayne Ye  Saturday, February 26, 2011Category:Programming»Web Development»HTML/CSS 

Background

Web Storage (also named Dom storage) is a brand new mechanism of storing temporary/permanent data introduced in HTML5 to replace cookie, it contains two new DOM objects: sessionStoragy and localStorage), in Web Storage Spec, Ian Hickson documented that Web Storage are intended to solve two cases that "not handled well by Cookie", they are:

  1. The first is designed for scenarios where the user is carrying out a single transaction, but could be carrying out multiple transactions in different windows at the same time.
  2. The second storage mechanism is designed for storage that spans multiple windows, and lasts beyond the current session. In particular, Web applications may wish to store megabytes of user data, such as entire user-authored documents or a user's mailbox, on the client side for performance reasons.

sessionStorage and localStorage are introduced by W3 in HTML5 to solve problems above, let's begin with a review of how Cookie currently works.


Current HTTP State Storage – Cookie

Mechanism

An HTTP Cookie was a set of key/value pairs which an HTTP web server requests a concrete client browser (i.e. User Agent - UA) to store on client's hard disk, when the UA request to the web server further, UA will wrap all the cookie data within the HTTP request header as long as following conditions are all satisfied:

  1. The cookie data has not expired.
  2. The requested domain is under exactly the same domain when cookie was stored.
  3. The requested path under the domain is the same one where cookie was stored.

Once the cookie expires, browser will delete it from local hard disk.

A common cookie example:

  1. An end user types www.foo.net in a browser's navigation bar and hit enter.
  2. www.foo.net returns HTTP status 200 message below (In the Green part, web server expected client browser to store two Cookie key/value pairs: WayneKey1=value1;WayneKey2=Value2, they could be accessible from the entire domain, and they will expire after 1 year):

    HTTP/1.1 200 OK
    Content-type: text/html
    Set-Cookie: WayneKey1=value1;WayneKey2=Value2;domain=www.foo.net; expires=Tue, 24-Feb-2012 07:13:22 GMT; path=/; HttpOnly
     
    (Response HTTP body)


View Post»



Permalink:http://wayneye.com/Blog/HTML5-Web-Storage-In-Essence
Tag:

Significant Enhancement in Internet Explorer 9
 
2170 Views 4 Comments
Written by Wayne Ye  Friday, February 18, 2011Category:Programming»Web Development»HTML/CSS 

Background

Microsoft announced Internet Explorer 9 Release Candidate on  Feb 10th, 2011, RC indicates except bug fixing, there would not have big changes before the final RTM. Since I've been keeping a watchful eye on IE9 from its very first preview version, I would like to write a post about its significant enhancement from a developer's point of view, I intend to summarize most significant enhancement points of IE9 listed below:

  • Enhanced performance
    1. The New Chakra JavaScript Engine
    2. Hardware Acceleration
  • Enhanced Web Standard Support
    1. HTML5 (huge number of new attributes support and Web Storage support)
    2. CSS3 (border-radius, ::selection pseudo-element, )
    3. W3 standard Geolocaltion API
  • Windows 7 Integration
    1. Website customizable TaskBar Jumplist.

By achieving new features above, IE9 will absolutely be the fastest and best Web Standard support version in the entire IE history.  

Walk through IE9 Enhancements

New JavaScript Engine – Chakra

IE9 team must be persistently working so hard on improving Chakra's performance, I picked following two paragraph  from Chakra Page on Wikipedia:

Microsoft's development of the engine was in response to evolving competing browsers, on which IE8 was lagging behind in terms of JavaScript processing speed.[3] SunSpider tests performed on November 18, 2009 showed the PDC version of IE9 executing scripts much faster than IE8, but slower than respectively Firefox 3.6, Chrome 4, and WebKit Nightly.[4] The same test performed on March 15, 2010 showed the first IE9 Platform Preview (using the then-current version of Chakra) to be faster than Firefox (with SpiderMonkey), but slower than respectively Safari (with SquirrelFish Extreme), Chrome (with V8), and Opera (with Carakan)

On February 8, 2011, the test showed the IE9 Release Candidate (using the current version of Chakra) to be faster than Safari, Firefox (with TraceMonkey), Opera, and Chrome.


View Post»



Permalink:http://wayneye.com/Blog/Significant-Enhancement-In-InternetExplorer9
Tag:

"Unique URL Pattern" in Ajax Web Application
 
1393 Views 0 Comments
Written by Wayne Ye  Wednesday, January 12, 2011Category:Programming»Web Development»JavaScript 

Testing: Can I really edit this?

Background

Few days ago one of my friend asked me how does Gmail change its URL while user operates inside it without page refreshing, I've no idea about that at that time, he then shared a link Ajax Pattern - Unique URLs which deep dives into this topic, as the article mentioned: Unique URL make your website's link "Bookmarkable, Linkable, Type-In-Able", plus Sharable IMHO, easy to be shared to Social network which is extremely important nowadays.

Implementation

The key technology to achieve the ""Unique URL" goal could be summarized into two points:
  1. If the content in the page has been updated by Ajax significantly enough, update the URL (location.hash) as well.
  2. // Ajax rendering all blog entries in page number 5
    location.hash = 'Blogs&Page5';
  3. Every time the Ajax page loads, JS should understand the


View Post»



Permalink:http://wayneye.com/Blog/Unique-URL-Pattern-In-Ajax
Tag:

IP Address to Geolocation
 
2531 Views 0 Comments
Written by Wayne Ye  Thursday, December 30, 2010Category:Programming»Web Development»Misc 

Background


Few months ago I found an interesting website: http://ipinfodb.com/, it provided API which could "translate" any IP Address into a geography location including City/Region/Country as well as latitude/longitude and time zone information, to invoke its API, a registered API key is required (which is free). Since beforehand I stored visitor's IP Addresses into my own database, I decided to utilize InfoDB API to store visitor's GEO locations.

Just few days ago, I casually emitted an idea: summarize those GEO location records and display them on Google Map, hum, it is feasible:)

So, the process is: Track visitor's IP addresses -> "Translate" them to Geography location -> Show them on Google Map!

(PS, I've been used Google Analytics for my Geek Place - http://WayneYe.com for more than two years, it is no double extremely powerful, and it already contains a feature "Map Overlay", however, due to privacy policy, Google Analytics does NOT display visitor's IP address, see http://www.google.com/support/analytics/bin/answer.py?hl=en&answer=86214).

Implementation


The first task I need to do is track visitor's IP Address, most of the time, user visits a website in browser submits an HTTP GET request (an HTTP data package) based on Transmission Control Protocol (most of the time) , browser passed the ball to DNS server and DNS server delivered the request to the designation - the web host server, during the process, the original Http request was possibly transferred through a number of routers/proxies and many other stuff, the request's header information might have been updated: Via (Standard HTTP request header) or X-Forwarded-For (non-standard header but widely used), could be the original ISP's information/IP Address OR possibly one of the proxy's IP Address.

So, usually the server received the request and saw Via/X-Forwarded-For header information, it got to know visitor's IP address (NOT all the time, some times ISP's IP address), in ASP.NET, it is simply to call Request.UserHostAddress, however, we can never simply trust this because of two major reasons:

  1. Malicious application can forge HTTP request with modified X-Forwareded-To header (for example: X-Forwarded-To: dangerous code), if you are unlucky to trust it and have it inserted into Database, then SQL Injection hole will be utilized by Malicious application.

  2. Not all the visitors are human-been, part of them could be search engine spiders, I must distinguish human visitors and spiders, otherwise for example, I will be happy to see a lot of "visitors" came from "Mountain View, CA" ^_^.


For #1: I use regular expression to validate the string I got from Request.UserHostAddress:
public static Boolean IsValidIP(string ip)
{
if (System.Text.RegularExpressions.Regex.IsMatch(ip, "[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"))
{
string[] ips = ip.Split('.');
if (ips.Length == 4 || ips.Length == 6)
{
if (System.Int32.Parse(ips[0]) < 256 && System.Int32.Parse(ips[1]) < 256
& System.Int32.Parse(ips[2]) < 256 & System.Int32.Parse(ips[3]) < 256)
return true;
else
return false;
}
else
return false;
}
else
return false;
}

If the result is "0.0.0.0", I will


View Post»



Permalink:http://wayneye.com/Blog/IPAddress-To-Geolocation
Tag:

把Blog里的照片全部加上圆角效果吧:)
 
751 Views 0 Comments
Written by Wayne Ye  Sunday, May 4, 2008Category:Programming»Web Development»HTML/CSS 

前几天在网上找到这么个酷酷的玩意,用JS给图片加上各种各样的圆角效果,官方主页:

http://www.netzgesta.de/corner/

看后顿时觉得很酷,今天周末,有时间来搞搞这个:)

读了官网的说明后发现很简单,下载corner.js(本地下载 ),然后页面include后直接使用class="自己挑一个喜欢的class"就ok了。

那么这里有个问题,如果你的Blog上线已有时日(比如鄙博),难道要手动更新你之前所有Blog里的图片代码给它们加上 class??

呵呵,这点事根本不能称之为问题:)当然是加段JS脚本给动态注册className喽,鄙播采用了Div+Css架构以及 MasterPage,所有的Blog都包含于一个名为“ContentPlaceHolder”对Div中


View Post»



Permalink:http://wayneye.com/ViewBlog.aspx?BlogID=21
Tag: