Just a quick post about IE.Next - SunSpider could score a bit better (not compared with other browsers) but the render speed, css direct/text visualization, plus events propagation, is about 2 times slower than beta 2 and 7
Guys ... just 3 words: what the hell!
behind the design
My JavaScript book is out!
Don't miss the opportunity to upgrade your beginner or average dev skills.
Tuesday, January 27, 2009
Monday, January 26, 2009
PAMPA-J calls for tests
More downloads, and as usual more problems caused by different configurations.
I would like to leave a single official 1.0 release in Google Code PAMPA-J Project page but I need your tests to do this.
Test I would like to perform with your configurations:
All above tests passed without problems for me, but I would like to be sure it works properly in other environments. Would you help me? Cheers :-)
I would like to leave a single official 1.0 release in Google Code PAMPA-J Project page but I need your tests to do this.
Test I would like to perform with your configurations:
- PAMPA starts (default configuration: Apache, MySQL, PHP, Jaxer)
- PAMPA works from every folder (Desktop, Documents, others)
- PAMPA closes processes on stop and/or exit
- PAMPA works from network as well (old version could be launched from another PC without problems and respecting paths)
All above tests passed without problems for me, but I would like to be sure it works properly in other environments. Would you help me? Cheers :-)
Saturday, January 24, 2009
PAMPA 1.0 - Jaxer included!
Update - Windows Home Fixed!
Version 1.0b contains hot fixes for Window$ Home Edition plus some little change to make PAMPA more robust than before during process managment.
If you already downloaded version 1.0 you can download only the Tray executable and rename it as PAMPA.exe
Please tell me if you have still problems, hoping this b version will be the final 'till 1.1 ;-)
Update
Final Version 1.0 now served via Google Code ;-)
I am proud to announce thefirst Release Candidate final 1.0 release of my tiny precious PAMPA, jumped from version 0.7 to 1.0 and rewrote from the scratch considering every suggestion its users gave me during these years (project born in 2006 and completely revisited for version 1.0)
PAMPA means Portable Apache, MySQL, and PHP Application, in this release with Aptana Jaxer included!
(shell I consider PAMPA-J a portable Aptana Cloud?)
PAMPA is the first customizable and portable WAMP environment that includes Jaxer and that is completely free (but of course donations are always appreciated).
You can launch PAMPA from an USB driver, a CD-ROM (without native database write capabilities), an external Hard Disk, your Hard Disk itself, configuring MySQL data folders, session folders via php.ini, Apache folders, Jaxer folders, and reading logs, changing configuration, in a truly simple way.
For some reason Google Code policy is to ask sourceforge about projects with the same name, so in Google Code I had to change PAMPA project name into PAMPA-J, considering that somebody created an empty PAMPA project in sourceforge 1 year ago, while PAMPA exists at least since February 2006 ...anyway, the link I provided already should not show the RC release yet, while this one, directly from the svn, is the unofficial Release Candidate 1 Direct Download
All you need to do is to choose a folder to decompress PAMPA and then launch PAMPA.exe from that folder, wherever it is.
The result, by default, should be a fully configured Apache, MySQL, PHP, and Jaxer environment for your Window$ 2000/XP/Vista/7 Operating System.
I am working to create a better "splash page" to introduce PAMPA, but right now the Release Candidate shows simply the Document Root with links for some file, Jaxer public folder included ;-)
Why all this effort for a Release Candidate?
Because I am looking forward for your feedback, in order to release the first portable WAMP plus Jaxer environment with all you need to develop for your own or for distributions your applications and with all you need (in a reasonable way :D)
PAMPA-J is out, have fun! 8-)
Version 1.0b contains hot fixes for Window$ Home Edition plus some little change to make PAMPA more robust than before during process managment.
If you already downloaded version 1.0 you can download only the Tray executable and rename it as PAMPA.exe
Please tell me if you have still problems, hoping this b version will be the final 'till 1.1 ;-)
Update
Final Version 1.0 now served via Google Code ;-)
I am proud to announce the
What is PAMPA-J
PAMPA means Portable Apache, MySQL, and PHP Application, in this release with Aptana Jaxer included!
(shell I consider PAMPA-J a portable Aptana Cloud?)
What does it mean: Portable
PAMPA is the first customizable and portable WAMP environment that includes Jaxer and that is completely free (but of course donations are always appreciated).
You can launch PAMPA from an USB driver, a CD-ROM (without native database write capabilities), an external Hard Disk, your Hard Disk itself, configuring MySQL data folders, session folders via php.ini, Apache folders, Jaxer folders, and reading logs, changing configuration, in a truly simple way.
Where is it?
For some reason Google Code policy is to ask sourceforge about projects with the same name, so in Google Code I had to change PAMPA project name into PAMPA-J, considering that somebody created an empty PAMPA project in sourceforge 1 year ago, while PAMPA exists at least since February 2006 ...
How does it work?
All you need to do is to choose a folder to decompress PAMPA and then launch PAMPA.exe from that folder, wherever it is.
The result, by default, should be a fully configured Apache, MySQL, PHP, and Jaxer environment for your Window$ 2000/XP/Vista/7 Operating System.
What's in
- Apache 2.2.11
- MySQL 5.1.30-community
- PHP 5.3.0 alpha 3 (RC1)
- Jaxer 1.0.2.4347
- phpMyAdmin 3.1.2
Because I am looking forward for your feedback, in order to release the first portable WAMP plus Jaxer environment with all you need to develop for your own or for distributions your applications and with all you need (in a reasonable way :D)
PAMPA-J is out, have fun! 8-)
Friday, January 23, 2009
Quick Tip: C# GZip content
A quick post with a simple trick that let us reduce instantly every Ajax interaction over our C#.NET application:
The good part is that precedent code, whenever we were using Response.Write, became automatically compatible. Above code could be used to serve JavaScript or css files too:
That's it :-)
P.S. for file serving I suggest a cache system for pre gzipped files
[-] public void GZResponse() {
if(-1 < Convert.ToString(Request.ServerVariables["HTTP_ACCEPT_ENCODING"]).IndexOf("gzip")){
Response.AddHeader("Content-Encoding", "gzip");
Response.Filter = new System.IO.Compression.GZipStream(
Response.Filter,
System.IO.Compression.CompressionMode.Compress
);
}
}
The good part is that precedent code, whenever we were using Response.Write, became automatically compatible. Above code could be used to serve JavaScript or css files too:
[+] public void GZResponse(){}
[-] protected void Page_Load(object sender, EventArgs e)
{
GZResponse();
Response.AddHeader("Content-Type", "text/javascript");
Response.WriteFile("jquery.min.js");
}
That's it :-)
P.S. for file serving I suggest a cache system for pre gzipped files
Thursday, January 15, 2009
ellipse and circle for canvas 2d context
These days I am working inside an ExtJS panel to create some sophisticated drawing stuff, and I discovered (too late ...) that there is almost nothing in canvas 2d context to draw circle or ellipse.
That's why I have extended Google excanvas library and/or native canvas 2d context prototype to let us create circles and ellipse in the same simple way we can create rectangles.
Here the extended proto:
The last part is to obtain the same behavior with any browser and runtime create canvas:
SImple and efficient? I hope so, since I spent more than a couple of minutes to be able to create a perfect circle via 1/4 of a rectangle (square ... but how could I remember the bloody constant to do that?) :P
P.S. I remind you that the simplest function to create a circle via a center is canvas.arc(x, y, radius, 0, Math.PI*2); and that this proto create a circle inside a specified square but ithout the same arc performances ( anyway, runtime rendering in IE and my personal version of excanvas even faster than FireFox 3 ... anybody interested? :-) )
That's why I have extended Google excanvas library and/or native canvas 2d context prototype to let us create circles and ellipse in the same simple way we can create rectangles.
Here the extended proto:
(function(){
// Andrea Giammarchi - Mit Style License
var extend = {
// Circle methods
circle:function(aX, aY, aDiameter){
this.ellipse(aX, aY, aDiameter, aDiameter);
},
fillCircle:function(aX, aY, aDiameter){
this.beginPath();
this.circle(aX, aY, aDiameter);
this.fill();
},
strokeCircle:function(aX, aY, aDiameter){
this.beginPath();
this.circle(aX, aY, aDiameter);
this.stroke();
},
// Ellipse methods
ellipse:function(aX, aY, aWidth, aHeight){
var hB = (aWidth / 2) * .5522848,
vB = (aHeight / 2) * .5522848,
eX = aX + aWidth,
eY = aY + aHeight,
mX = aX + aWidth / 2,
mY = aY + aHeight / 2;
this.moveTo(aX, mY);
this.bezierCurveTo(aX, mY - vB, mX - hB, aY, mX, aY);
this.bezierCurveTo(mX + hB, aY, eX, mY - vB, eX, mY);
this.bezierCurveTo(eX, mY + vB, mX + hB, eY, mX, eY);
this.bezierCurveTo(mX - hB, eY, aX, mY + vB, aX, mY);
this.closePath();
},
fillEllipse:function(aX, aY, aWidth, aHeight){
this.beginPath();
this.ellipse(aX, aY, aWidth, aHeight);
this.fill();
},
strokeEllipse:function(aX, aY, aWidth, aHeight){
this.beginPath();
this.ellipse(aX, aY, aWidth, aHeight);
this.stroke();
}
};
for(var key in extend)
CanvasRenderingContext2D.prototype[key] = extend[key];
if(!this.G_vmlCanvasManager)
G_vmlCanvasManager = {init:function(){}, initElement:function(el){return el}};
})();
The last part is to obtain the same behavior with any browser and runtime create canvas:
var myCanvas = G_vmlCanvasManager.initElement(document.createElement("canvas"));
SImple and efficient? I hope so, since I spent more than a couple of minutes to be able to create a perfect circle via 1/4 of a rectangle (square ... but how could I remember the bloody constant to do that?) :P
P.S. I remind you that the simplest function to create a circle via a center is canvas.arc(x, y, radius, 0, Math.PI*2); and that this proto create a circle inside a specified square but ithout the same arc performances ( anyway, runtime rendering in IE and my personal version of excanvas even faster than FireFox 3 ... anybody interested? :-) )
Saturday, January 10, 2009
Internet Explorer Object watch
Update
As Luke suggested, there is a method remove in the watcher that should solver leaks problem while the new version should be supported by most recent Opera, Safari, FireFox, and Internet Explorer.
Main updates:
----------------------------------------------
We all complain about IE and its non-standard attitude, this time I would like to introduce a non standard feature, as Object.prototype.watch is, for Internet Explorer.
The watch method allows validation, control, monitoring, over a generic object.
This means that we can control properties assignment with one, or more, callbacks.
I used a weird strategy to implement this feature in Internet Explorer and it is based on DOM and its IE feature called onpropertychange.
Accordingly, it was not possible to create an Object.prototype.watch, while it was simple to implement a createWatcher callback.
A first example, based on precedent one, is this one:
Another example is based on validation, or better, a one shot assignment over the watcher:
Cool?
The main one is that the for in loop will not work as expected over a watcher element because it is a DOM node and it will expose every property.
Another one could be about memory leaks and/or low execution, since there are a couple of things to do during assignment.
The good part is that the watcher and the watched will have the same property value, except for those attributes that we cannot modify in a DOM node (style, for example).
Last but not least, happy new year! :D
As Luke suggested, there is a method remove in the watcher that should solver leaks problem while the new version should be supported by most recent Opera, Safari, FireFox, and Internet Explorer.
Main updates:
- the watcher is always another object and not the original one
- to safely destroy the watcher use its destroy method and then delete it
----------------------------------------------
We all complain about IE and its non-standard attitude, this time I would like to introduce a non standard feature, as Object.prototype.watch is, for Internet Explorer.
What is watch and why we need it
The watch method allows validation, control, monitoring, over a generic object.
This means that we can control properties assignment with one, or more, callbacks.
var man = {};
man.watch("name", function(propertyName, oldValue, newValue){
// propertyName: name
// oldValue: undefined if it is the first time, the old one otherwise
// newValue: new assigned value
return "Mr " + newValue;
});
man.name = "Andrea";
alert(man.name); // Mr Andrea
watch for Internet Explorer, about my implementation
I used a weird strategy to implement this feature in Internet Explorer and it is based on DOM and its IE feature called onpropertychange.
Accordingly, it was not possible to create an Object.prototype.watch, while it was simple to implement a createWatcher callback.
(function(watch, unwatch){
createWatcher = watch && unwatch ?
// Andrea Giammarchi - Mit Style License
function(Object){
var handlers = [];
return {
destroy:function(){
handlers.forEach(function(prop){
unwatch.call(this, prop);
}, this);
delete handlers;
},
watch:function(prop, handler){
if(-1 === handlers.indexOf(prop))
handlers.push(prop);
watch.call(this, prop, function(prop, prevValue, newValue){
return Object[prop] = handler.call(Object, prop, prevValue, newValue);
});
},
unwatch:function(prop){
var i = handlers.indexOf(prop);
if(-1 !== i){
unwatch.call(this, prop);
handlers.splice(i, 1);
};
}
}
}:(Object.prototype.__defineSetter__?
function(Object){
var handlers = [];
return {
destroy:function(){
handlers.forEach(function(prop){
delete this[prop];
}, this);
delete handlers;
},
watch:function(prop, handler){
if(-1 === handlers.indexOf(prop))
handlers.push(prop);
if(!this.__lookupGetter__(prop))
this.__defineGetter__(prop, function(){return Object[prop]});
this.__defineSetter__(prop, function(newValue){
Object[prop] = handler.call(Object, prop, Object[prop], newValue);
});
},
unwatch:function(prop){
var i = handlers.indexOf(prop);
if(-1 !== i){
delete this[prop];
handlers.splice(i, 1);
};
}
};
}:
function(Object){
function onpropertychange(){
var prop = event.propertyName,
newValue = empty[prop]
prevValue = Object[prop],
handler = handlers[prop];
if(handler)
attachEvent(detachEvent()[prop] = Object[prop] = handler.call(Object, prop, prevValue, newValue));
};
function attachEvent(){empty.attachEvent("onpropertychange", onpropertychange)};
function detachEvent(){empty.detachEvent("onpropertychange", onpropertychange);return empty};
var empty = document.createElement("empty"), handlers = {};
empty.destroy = function(){
detachEvent();
empty.parentNode.removeChild(empty);
empty = handlers = null;
};
empty.watch = function(prop, handler){handlers[prop] = handler};
empty.unwatch = function(prop){delete handlers[prop]};
attachEvent();
return (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(empty);
}
)
;
})(Object.prototype.watch, Object.prototype.unwatch);
A first example, based on precedent one, is this one:
var // original object
man = {},
// create its watcher
manWatcher = createWatcher(man);
manWatcher.watch("name", function(propertyName, oldValue, newValue){
return "Mr " + newValue;
});
// assign name property
manWatcher.name = "Andrea";
// retrieve original object property
alert(man.name); // Mr Andrea
Another example is based on validation, or better, a one shot assignment over the watcher:
var obj = {},
watcher = createWatcher(obj);
watcher.watch("test", function(prop, oldValue, newValue){
return oldValue === undefined ? newValue : oldValue;
});
watcher.test = "one assignment";
watcher.test = "never again";
alert(obj.test); // one assignment
Cool?
About limits
The main one is that the for in loop will not work as expected over a watcher element because it is a DOM node and it will expose every property.
Another one could be about memory leaks and/or low execution, since there are a couple of things to do during assignment.
The good part is that the watcher and the watched will have the same property value, except for those attributes that we cannot modify in a DOM node (style, for example).
Last but not least, happy new year! :D
Wednesday, December 24, 2008
External selectors as engines and how to create your own library
With "Sizzle event", the challenge about libraries will move from the coolest/fastest selector engine into the coolest/fastest way to use it for library purpose.
Since Sizzle will be just one of them, thanks to our natural behavior ( read: re-create the wheel ) it is possible that there will be more selector engines around the net.
So, why we could not create our own library that does just what we need and nothing else, maintaining a decent size and performing like a jaguar :D ???
Here a truly basic example about how to create your own library, basing it over a generic selector engine or generic library (or just its engine, if you prefer one)
The main limit is the engine itself, or better, arguments that the engin could accept.
If we change engine and this accepts different arguments or same arguments in a different way, we need to change every call to our library but at least everything else will work without problems.
For this reason it is reasonble to choose a common engine arguments model, like Sizzle, for example, presuming other engine will accept the same list of options and will produce an array like result.
Am I suggesting to avoid famous/common library? Absolutely no, I simply think the selector engine is the most important thing for whatever DOM purpose library :-)
Since Sizzle will be just one of them, thanks to our natural behavior ( read: re-create the wheel ) it is possible that there will be more selector engines around the net.
So, why we could not create our own library that does just what we need and nothing else, maintaining a decent size and performing like a jaguar :D ???
Here a truly basic example about how to create your own library, basing it over a generic selector engine or generic library (or just its engine, if you prefer one)
// our wonderful library constructor
function myQuery(){
// just in case we prefer another name for the constructor
// this code is "name proof"
var callee = arguments.callee;
return this instanceof callee ?
this :
callee.prototype.init.apply(new callee, arguments)
;
};
// add some native prototype to created array like instances
// a common pattern for DOM based libraries
with(Array.prototype)
myQuery.prototype = {
constructor:myQuery,
length:0,
pop:pop,
push:push,
shift:shift,
slice:slice,
sort:sort,
splice:splice,
unshift:unshift
};
// add "not standard yet array prototypes", if necessary, or our own cool proottypes
myQuery.prototype.forEach = Array.prototype.forEach || function(Function, self){
for(var i = 0, length = this.length; i < length; i++)
(i in this) && Function.call(self, this[i], i, this);
};
// define the init prototype to use the pre defined engine
myQuery.prototype.init = function(){
var self = this.engine.apply(null, arguments);
this.push.apply(this, self instanceof Array ? self : this.slice.call(self, 0));
return this;
};
// define the engine for this library
myQuery.prototype.engine = Sizzle; // or jQuery
onload = function(){
// enjoy your lib
myQuery(".foo .bar").forEach(function(HTMLElement){
HTMLElement.innerHTML = "Hello Lib!";
});
};
Summary
The main limit is the engine itself, or better, arguments that the engin could accept.
If we change engine and this accepts different arguments or same arguments in a different way, we need to change every call to our library but at least everything else will work without problems.
For this reason it is reasonble to choose a common engine arguments model, like Sizzle, for example, presuming other engine will accept the same list of options and will produce an array like result.
Am I suggesting to avoid famous/common library? Absolutely no, I simply think the selector engine is the most important thing for whatever DOM purpose library :-)
Tuesday, December 23, 2008
Visual Studio 2008 - The good part
... whatever I said in the precedent post, at least VS9 let us extend it and create macros as well.
Unfortunately, I could not create a macro in C# so I had to use a language that I do not like at all, Visual Basic, and the result is an alpha macro that allows us to create "more clever" regions and outline for brackets as well.
There is another macro that goes around since Visual Studio 2005 but it has some bug and/or problem with nested regions plus it does not allow us to write directly in the region what the region is about
At the same time that macro put every region, nested or not, at the beginning of the line. It is not such a big problem, but I prefer this version.
This is absolutely experimental and there are hundreds of problems, but for a couple of files it is doing its job.
Christmas, holidays, relax, if it is possible, and a better parser (a char by char via VB, I cannot even imagine me doing it!!!) so be patience please, and enjoy this alpha release :)
Unfortunately, I could not create a macro in C# so I had to use a language that I do not like at all, Visual Basic, and the result is an alpha macro that allows us to create "more clever" regions and outline for brackets as well.
More clever regions
There is another macro that goes around since Visual Studio 2005 but it has some bug and/or problem with nested regions plus it does not allow us to write directly in the region what the region is about
//#region whatever
...
//#endregion
--- to obtain
//#region whatever[...]
--- instead of
// another "boring" comment over the region
[...]
At the same time that macro put every region, nested or not, at the beginning of the line. It is not such a big problem, but I prefer this version.
Brackets outline
This is absolutely experimental and there are hundreds of problems, but for a couple of files it is doing its job.
What's next
Christmas, holidays, relax, if it is possible, and a better parser (a char by char via VB, I cannot even imagine me doing it!!!) so be patience please, and enjoy this alpha release :)
' JavaScript macro for bits and bops alpha version
' by Andrea Giammarchi - WebReflection.blogspot.com
Option Strict Off
Option Explicit Off
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Collections
Public Module JSMacros
Sub OutlineBrackets()
Outline("Brackets")
End Sub
Sub OutlineRegions()
Outline("Regions")
End Sub
Private Function Outline(ByVal what As String)
Dim REGION_START As String = "//#region"
Dim REGION_END As String = "//#endregion"
If what = "Brackets" Then
REGION_START = "{"
REGION_END = "}"
ElseIf what = "Regions" Then
REGION_START = "//#region"
REGION_END = "//#endregion"
End If
Dim selection As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
Dim selections As ArrayList = New ArrayList
Dim regions As Stack
Dim current As Stack
Dim endIndex As Integer
Dim startIndex As Integer
Dim text As String
selection.StartOfDocument()
selection.SelectAll()
text = selection.Text
If text.Chars(text.Length - 1) <> vbCr Then
selection.EndOfDocument()
selection.Insert(vbCr)
text += vbCr
End If
regions = FindRegions(text, REGION_START, REGION_END)
If what = "Brackets" Then
OutlineBracketsLoop(REGION_START, REGION_END, regions, selections, text, 0, 0, 0, regions.Count(), New Stack)
ElseIf what = "Regions" Then
OutlineRegionsLoop(REGION_START, REGION_END, regions, selections, text, 0, 0, 0, regions.Count(), New Stack)
End If
SetOutline(selection, selections)
selection.StartOfDocument()
End Function
Private Function CalcLineNumber(ByRef text As String, ByVal i As Integer)
Dim lineNumber As Integer = 1
While 0 < i
i -= 1
If text.Chars(i) = vbCr Then
lineNumber += 1
End If
End While
Return lineNumber
End Function
Private Function FindPosition(ByRef text As String, ByVal i As Integer)
Dim position As Integer = 0
While 0 < i
i -= 1
position += 1
If i = 0 Or text.Chars(i) = vbCr Then
Exit While
End If
End While
Return position
End Function
Private Function FindRegions(ByRef text As String, ByRef REGION_START As String, ByRef REGION_END As String)
Dim result As Stack = New Stack()
Dim pos As Stack = New Stack(2)
Dim startIndex As Integer = 0
Dim endIndex As Integer
Dim index As Integer = 0
Dim subValue As String = ""
Do
startIndex = text.IndexOf(REGION_START, startIndex)
If startIndex = -1 Then
Exit Do
End If
pos.Push(startIndex)
startIndex = startIndex + REGION_START.Length
index = startIndex
endIndex = text.IndexOf(REGION_END, startIndex)
If endIndex = -1 Then
MsgBox("Endless Region")
Exit Do
End If
Do
index = text.IndexOf(REGION_START, index)
If index = -1 Or endIndex < index Then
pos.Push(endIndex)
result.Push(pos)
pos = New Stack(2)
Exit Do
Else
endIndex = text.IndexOf(REGION_END, endIndex + REGION_END.Length)
index = index + REGION_START.Length
End If
Loop
Loop
Return result
End Function
Private Function OutlineBracketsLoop(ByRef REGION_START As String, ByRef REGION_END As String, ByRef regions As Stack, ByRef selections As ArrayList, ByRef text As String, ByVal startIndex As Integer, ByVal endIndex As Integer, ByVal i As Integer, ByVal length As Integer, ByVal current As Stack)
Dim startLine As Integer
Dim endLine As Integer
While i < length
current = regions.Pop
endIndex = current.Pop
startIndex = current.Pop
startLine = CalcLineNumber(text, startIndex)
endLine = CalcLineNumber(text, endIndex)
If startLine < endLine Then
selections.Add(startLine)
selections.Add(FindPosition(text, startIndex) - 1)
selections.Add(endLine)
selections.Add(FindPosition(text, endIndex))
End If
i += 1
End While
End Function
Private Function OutlineRegionsLoop(ByRef REGION_START As String, ByRef REGION_END As String, ByRef regions As Stack, ByRef selections As ArrayList, ByRef text As String, ByVal startIndex As Integer, ByVal endIndex As Integer, ByVal i As Integer, ByVal length As Integer, ByVal current As Stack)
Dim tmpIndex As Integer
While i < length
current = regions.Pop
endIndex = current.Pop
startIndex = current.Pop
tmpIndex = startIndex + REGION_START.Length
selections.Add(CalcLineNumber(text, startIndex))
selections.Add(1 + FindPosition(text, startIndex) + REGION_START.Length + text.Substring(tmpIndex, text.IndexOf(vbCr, startIndex) - tmpIndex).Length)
selections.Add(CalcLineNumber(text, endIndex) + 1)
selections.Add(1)
i += 1
End While
End Function
Private Function SetOutline(ByRef selection As EnvDTE.TextSelection, ByRef selections As ArrayList)
Dim i As Integer = 0
Dim length As Integer = selections.Count()
While i < length
selection.MoveToLineAndOffset(selections.Item(i), selections.Item(i + 1))
selection.MoveToLineAndOffset(selections.Item(i + 2), selections.Item(i + 3), True)
selection.OutlineSection()
i += 4
End While
End Function
End Module
Saturday, December 20, 2008
Visual Studio 2008 and JavaScript: the worst couple ever
We are using Visual Studio 2008 Team Edition at work and it is great for our C# plus SQLServer application, but I am working entirely with JavaScript and every time my files grow up "too much" I start having headache scrolling up and down thousands of line of code.
A basic function that even a small editor like Notepad++ has, the plus/minus sign to close functions closures, does not exists.
You should try to create your own macro, in VB "of course", and call it every time.
As alternative, I added the file extension js in the option with HTML Editor as default editor to let me do something like this
Above start and end comment allows me to close code blocks and everything inside will be highlighted because the editor consider it as an HTML JavaScript tag:
it's true, HTML has open/close blocks while JavaScript does not.
The "fantastic" debugger is nothing that better than the one you can find inside Internet Explorer 8, the only point is that it is integrated with the rest of the project so you can debug both JavaScript and C# at the same time ... without this big effort.
I use FireBug and/or Chrome console indeed, since I do not need to monitor C# that much, and that's it, client side debug feature completely useless under IE ( and I downloaded the version 8 beta 2 yesterday so I can use its debugger instead of launching another local server for client side debug ... )
The intellisense sucks, it does not work automatically as is for C# or other languages or as is for Eclipse or Aptana, you have to put useless syntax in the top of the file to tell the big IDE where are other files.
The suggestion is so clever that if you have a property whose name starts with el, the IDE will autmatically put an else
The internal parser does not recognize properly functions as objects, and inheritance is not part of the suggestion ... you should try to disable it if you want to code faster instead of correct IDE suggestions.
In few words, I still wonder why Microsoft is doing everything to discourage the usage of JavaScript and I can't wait to find a valid alternative to integrate my JavaScript projects into source control without being constricted to use the best IDE for C# and the worst ever for JavaScript: Visual Studio 2008
Kind Regards
A basic function that even a small editor like Notepad++ has, the plus/minus sign to close functions closures, does not exists.
You should try to create your own macro, in VB "of course", and call it every time.
As alternative, I added the file extension js in the option with HTML Editor as default editor to let me do something like this
//#region MyConstructor <script>
... my code
//#endregion </stript>
Above start and end comment allows me to close code blocks and everything inside will be highlighted because the editor consider it as an HTML JavaScript tag:
it's true, HTML has open/close blocks while JavaScript does not.
The "fantastic" debugger is nothing that better than the one you can find inside Internet Explorer 8, the only point is that it is integrated with the rest of the project so you can debug both JavaScript and C# at the same time ... without this big effort.
I use FireBug and/or Chrome console indeed, since I do not need to monitor C# that much, and that's it, client side debug feature completely useless under IE ( and I downloaded the version 8 beta 2 yesterday so I can use its debugger instead of launching another local server for client side debug ... )
The intellisense sucks, it does not work automatically as is for C# or other languages or as is for Eclipse or Aptana, you have to put useless syntax in the top of the file to tell the big IDE where are other files.
The suggestion is so clever that if you have a property whose name starts with el, the IDE will autmatically put an else
myObject.else // by the ide
The internal parser does not recognize properly functions as objects, and inheritance is not part of the suggestion ... you should try to disable it if you want to code faster instead of correct IDE suggestions.
In few words, I still wonder why Microsoft is doing everything to discourage the usage of JavaScript and I can't wait to find a valid alternative to integrate my JavaScript projects into source control without being constricted to use the best IDE for C# and the worst ever for JavaScript: Visual Studio 2008
Kind Regards
Wednesday, December 17, 2008
outerHTML for almost every browser ... if you need it ...
We all have to deal with memory leaks problem and apparently a good way to be sure that an HTMLElement has been removed from its "flow" is the outerHTML assignemnt (thanks Ariel for the suggestion)
If the element is not a document.body or another body parent node, Internet Explorer will "extract" that element from its context, if any, and if there are no other references for that element the null assignment will, theoretically, complete the opera, hopefully solving memory leaks problem for that node as well ...
Every library has a "swap" or replace method to quickly change an element, but even if we all know that innerHTML is the fastest way to insert content, few libraries use outerHTML to replace nodes, that as far as I know, should be "that fast" in IE as innerHTML is:
pro and cons are the same of innerHTML and the reference is lost as is for Internet Explorer, whenever we decide to use this dirty approach to remove or change elements in the DOM. A last example?
element.outerHTML = "";
element = null;
If the element is not a document.body or another body parent node, Internet Explorer will "extract" that element from its context, if any, and if there are no other references for that element the null assignment will, theoretically, complete the opera, hopefully solving memory leaks problem for that node as well ...
To remove ... but to replace too ...
Every library has a "swap" or replace method to quickly change an element, but even if we all know that innerHTML is the fastest way to insert content, few libraries use outerHTML to replace nodes, that as far as I know, should be "that fast" in IE as innerHTML is:
// traditional swap, the DOM way
function swap(oldNode, newNode){
var parentNode = oldNode.parentNode;
parentNode.insertBefore(newNode, oldNode);
parentNode.removeChild(oldNode);
};
// spaghetti swap, the outerHTML way
function swap(oldNode, newNode){
oldNode.outerHTML = newNode.outerHTML;
};
outerHTML ... both get and set
try{
HTMLElement.prototype.__defineGetter__.length;
(function(body, removeChild){
HTMLElement.prototype.__defineGetter__(
"outerHTML",
function(){
var self = body.appendChild(this.cloneNode(true)),
outerHTML = body.innerHTML;
body.removeChild(self);
return outerHTML;
}
);
HTMLElement.prototype.__defineSetter__(
"outerHTML",
function(String){
if(!String)
removeChild(this);
else if(this.parentNode){
body.innerHTML = String;
while(body.firstChild)
this.parentNode.insertBefore(body.firstChild, this);
removeChild(this);
body.innerHTML = "";
};
}
);
})(
document.createElement("body"),
function(HTMLElement){if(HTMLElement.parentNode)HTMLElement.parentNode.removeChild(HTMLElement);}
);
}catch(e){};
Conclusion
pro and cons are the same of innerHTML and the reference is lost as is for Internet Explorer, whenever we decide to use this dirty approach to remove or change elements in the DOM. A last example?
function change(strong){
strong.outerHTML = "not strong anymore";
strong = null;
};
onload = function(){
document.body.innerHTML = "click";
};
Saturday, December 06, 2008
A fast and crossbrowser function to make an Array
An absolutely common task present in almost every library, is to transform a generic collection/list of objects or DOM Elements into a friendly Array.
When we execute a piece of JavaScript in a web page, we can assume that we have at least one DOM element in that page, as the script itself for example, so it is always possible to obtain a collection of elements calling document.getElementsByTagName("script") or a generic ("*") in this case probably superflous considering the latter assumption.
The try catch is executed only once, the Array prototypes are cached once as well to guarantee cross libraries compatibility. The function is assigned differently for those browsers that can apply the slice prototype to the collection and those that cannot (mainly Internet Explorer).
Accepted parameters are two, inspired by Sizzle function, to allow us to concatenate elements into a collection.
The collection is transformed into an Array only if necessary, since it does not make sense to perform a slice call in every case.
Compatiblity? It should be every browser that supports try and catch statement :-)
Cases Scenario
- It is possible to apply directly an Array.prototype.slice call to quickly return an Array
- It is not possible at all apply every kind of Array prototype to the list
Cases scenario detection
When we execute a piece of JavaScript in a web page, we can assume that we have at least one DOM element in that page, as the script itself for example, so it is always possible to obtain a collection of elements calling document.getElementsByTagName("script") or a generic ("*") in this case probably superflous considering the latter assumption.
Cross browser and fast makeArray proposal
var makeArray = function(push, slice){
try{
// Andrea Giammarchi proposal
slice.call(document.getElementsByTagName("script"), 0);
return function(array, results){
array = array instanceof Array ? array : slice.call(array, 0);
results ? push.apply(results, array) : results = array;
return results
}
}catch(e){
return function(array, results){
if(!(array instanceof Array))
for(var ret = [], i = 0, length = array.length; i < length; i++)
ret[i] = array[i];
else
var ret = array;
results ? push.apply(results, ret) : results = ret;
return results
}
}
}(Array.prototype.push, Array.prototype.slice);
Summary
The try catch is executed only once, the Array prototypes are cached once as well to guarantee cross libraries compatibility. The function is assigned differently for those browsers that can apply the slice prototype to the collection and those that cannot (mainly Internet Explorer).
Accepted parameters are two, inspired by Sizzle function, to allow us to concatenate elements into a collection.
The collection is transformed into an Array only if necessary, since it does not make sense to perform a slice call in every case.
Compatiblity? It should be every browser that supports try and catch statement :-)
Wednesday, December 03, 2008
Stressfull procedure? Distribute your task!
Have you never been in troubles with frozen GIFs or unresponsive HTML?
Sometimes JavaScript could be used to perform really stressful task and a loop, a for in, or an each, could not be fast enough to make your DOM responsive.
What we need in this case is simply a closure to make sure references are consistent and our job will end up in the correct order.
This is a probably silly but I hope interesting function to make the DOM and generally the page more responsive:
We can call this functon in different ways, stating from the demo:
untill its more meaningful usage:
Another trick? The usage of the scope injected by each function:
People expect usability, we expect performances ... at the same time we would like to be able to show a progress, something, that indicate that the page is not completely blocked.
This is a simple way to solve the problem, portable enough, and customizable via closures ... I hope you'll enjoy it :)
Sometimes JavaScript could be used to perform really stressful task and a loop, a for in, or an each, could not be fast enough to make your DOM responsive.
What we need in this case is simply a closure to make sure references are consistent and our job will end up in the correct order.
This is a probably silly but I hope interesting function to make the DOM and generally the page more responsive:
Time = {
setTimeout:function(Stack, delay){
var self = this;
if(!delay)
delay = 1;
if(!(Stack instanceof Array))
Stack = [Stack];
setTimeout(function(){
Stack.shift().call(self);
if(0 < Stack.length)
setTimeout(arguments.callee, delay);
}, delay);
}
};
We can call this functon in different ways, stating from the demo:
Time.setTimeout([
function(){
alert("Hello");
},
function(){
alert("Distributed");
},
function(){
alert("Work");
}
]);
untill its more meaningful usage:
var distributed = [];
$("whatever").each(function(i, dom){
distributed.push(function(){
// your stuff to do with i or dom element
});
});
distributed.push(function(){
// your stuff to do after the each call
});
Time.setTimeout(distributed);
Another trick? The usage of the scope injected by each function:
$("whatever").each(function(i, dom){
var self = this;
distributed.push(function(){
return function(){
// your stuff to do with i or dom element
}.call(self);
});
});
Closures against Responsiveness
People expect usability, we expect performances ... at the same time we would like to be able to show a progress, something, that indicate that the page is not completely blocked.
This is a simple way to solve the problem, portable enough, and customizable via closures ... I hope you'll enjoy it :)
Tuesday, November 18, 2008
Ext JS - How to hack the JsonReader
I have a new job ( hooooray?! ) and I suggested Ext JS framework as web UI to focus more about Ajax, XML + XSLT data interactions rather than problems with CSS, events delegations, etc ... and I guess I am doing well, so well, that here I am with a simple tiny trick to hack an Ext.data.JsonReader instance, specially the root and the totalProperty params:
Especially for the paginator toolbar, the JsonReader is a must to surf a big amount of data without stressing too much both server and client sides.
One nice feature, or one clever way to make the root node customizable, is the usage of evaluated code via a new Function call.
If the root property ontains a dot, that property is retrieved via nested objec properties.
Thanks to this feature, it is possible to pre parse and pre generate the list that will be assigned as root Array, the one used inside the Grid, DataView, or whatever.Component is managing your interactions.
The trick to pass the returned object to an arbitrary function is this:
The callback suppose to be a valid function with a global scope that will return a filtered list of objects compatible with the column model or the data manager we chose.
The trick is based on their regexp that checks simply a dot or a square bracket "[" in the passed string.
That's it, let me discover better tricky stuff in the source and I'll post them :D
// directly from Ext JS 2.2 API site
// http://extjs.com/deploy/dev/docs/
new Ext.data.JsonReader({
totalProperty: "results", // The property which contains the total dataset size (optional)
root: "rows", // The property which contains an Array of row objects
id: "id" // The property within each row object that provides an ID for the record (optional)
})
Especially for the paginator toolbar, the JsonReader is a must to surf a big amount of data without stressing too much both server and client sides.
One nice feature, or one clever way to make the root node customizable, is the usage of evaluated code via a new Function call.
If the root property ontains a dot, that property is retrieved via nested objec properties.
...
root:"items[0].myList",
...
Thanks to this feature, it is possible to pre parse and pre generate the list that will be assigned as root Array, the one used inside the Grid, DataView, or whatever.Component is managing your interactions.
The trick to pass the returned object to an arbitrary function is this:
...
root:"toString.length||callback(obj)",
...
The callback suppose to be a valid function with a global scope that will return a filtered list of objects compatible with the column model or the data manager we chose.
The trick is based on their regexp that checks simply a dot or a square bracket "[" in the passed string.
That's it, let me discover better tricky stuff in the source and I'll post them :D
Thursday, October 30, 2008
3, 2, ... 1, ... Coming Soon!
Guys, I can't wait for Ubuntu 8.10 and what's up in the website?
The countdown now shows a "Coming Soon" message ... I mean, a little news about when is that difficult?
I know there is a kernel problem since 27 October, and i hope you updatedare updating the release to fix that problem with the 8.10 ... but shall you tell us more?
Kind Regards
And thank You :)
The countdown now shows a "Coming Soon" message ... I mean, a little news about when is that difficult?
I know there is a kernel problem since 27 October, and i hope you updated
Kind Regards
And thank You :)
Tuesday, October 28, 2008
jQuery plug-in distributed elements via If, ElseIf, and Else
After a couple of instant and consecutive releases, I ended up with a plug-in that fits minified into 240 bytes :)
Here is the official plug-in page, while this is the example page and this is the summary:
Here is the official plug-in page, while this is the example page and this is the summary:
;jQuery.fn.extend({
// Andrea Giammarchi - Mit Style Licence - V0.2
If:function(fn){
var __If__ = this.__If__ || this,
$ = __If__.filter(fn);
$.__If__ = __If__.filter(function(){return !~$.index(this)});
return $;
},
Else:function(){
return this.__If__;
},
Do:jQuery.fn.each
}); jQuery.fn.ElseIf = jQuery.fn.If;
Monday, October 27, 2008
jQuery If, ElseIf, and Else plugin
Update
Guys, I have to admit I created silly prototypes while all I need were much more simpler than I though :) Enjoy last version!
-------------------------------------
Try to imagine a page like this one:
.. and now try to imagine something like this:
... now, try to imagine I created a plugin like this:
... and now try to enjoy it :D
Kind Regards
Guys, I have to admit I created silly prototypes while all I need were much more simpler than I though :) Enjoy last version!
-------------------------------------
Try to imagine a page like this one:
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
</body>
.. and now try to imagine something like this:
function oddNumbers(){
// return true if element contain an odd number
return $(this).text() & 1;
};
$(function(){
$("div")
.If(function(){return $(this).text() == "3" || $(this).text() == "5"})
.text("match the 3 or 5 check")
.ElseIf(oddNumbers)
.text("odd numbers")
.ElseIf(function(){return $(this).text() == 2})
.Do(function(){ // if you need a closure ...
$(this).text("text is equal 2");
})
.ElseIf(function(){return $(this).text() == 6})
.text("match the 6 condition")
.Else()
.text("this is 4 or 8");
;
})
... now, try to imagine I created a plugin like this:
;jQuery.fn.extend({
// Andrea Giammarchi - Mit Style Licence - V0.1f
If:function(fn){
var $ = this.filter(fn);
$.__If__ = this.filter(function(){return !~$.index(this)});
return $;
},
ElseIf:function(fn){
var $ = this.__If__.filter(fn);
$.__If__ = this.__If__.filter(function(){return !~$.index(this)});
return $;
},
Else:function(){
return this.__If__;
},
Do:jQuery.fn.each
});
... and now try to enjoy it :D
Kind Regards
Thursday, October 23, 2008
Subclassing JavaScript Native String
Just a quick post about subclassing native String constructor.
All we need is to redefine valueOf and toString methods.
With incoming V8, TraceMonkey, Squirrelfish, and other (if any ...) advanced engines that transforms repeated code into machine one, performances wont be a problem anymore and everybdy could create its own implementation of the String.
Of course, these statements will be preserved:
while typeof will return an object but we can easily use another method such:
concat as other native methods willl work, but returned object, unfortunatly, wont be a $String.
All we need is to redefine valueOf and toString methods.
function $String(__value__){
this.length = (this.__value__ = __value__ || "").length;
};
with($String.prototype = new String)
toString = valueOf = function(){return this.__value__};
With incoming V8, TraceMonkey, Squirrelfish, and other (if any ...) advanced engines that transforms repeated code into machine one, performances wont be a problem anymore and everybdy could create its own implementation of the String.
Of course, these statements will be preserved:
var s = new $String("abc");
s instanceof String; // true
s.constructor === String; // true
while typeof will return an object but we can easily use another method such:
$String.prototype.type = function(){
return "string";
};
alert(typeof s); // object
alert(s && s.type()); // string
concat as other native methods willl work, but returned object, unfortunatly, wont be a $String.
Wednesday, October 22, 2008
Big Douglas begetObject revisited recycling a unique function
With the precedent post I realized I wrote a really tricky way to extend inline a function.Next code is the snippet summary:
Above code uses the closure itself to create the intermediate constructor.
The reason i chose this way to operate that task was: why should I use another function when I already have one that is the closure itself?
Well done, one function instead of two ... but wait a second, why should I create a different function everytime instead of recycle a single one?
In one of His historical posts, Big Douglas describes simple JavaScript inheritance and object cloning using an intermediate constructor. This is the Object.create function:
Above snippets is still used in I do not know how many JavaScript libraries or code over the net, to extends constructor prototypes or to create a clone of a generic object.
The snippet is clever, powerful, "perfect" for its purpose, but it creates many functions for each object and your JS engine, as your RAM, has not shields to prevent its aggressiveness when you use thousands of times that snippet.
This is a benchmark function example:
If we test above function with Douglas Object.create one, the result will be something like:
Next snippet is my revisited version of that function:
these are advantages about recycling the function:
While these are results with the same configuration:
Seems to be quite impressive, isn't it? Results are tremendously different with Internet Explorer, where the good old way lets the browser ask if it is the case to stop the script: thousands of milliseconds against approximately 1200 with my revision.
I tested my revision to extend constructors as well, and everything seems to be absolutely fine. This is the function, based on the precedent one:
Everything is about the clone strategy itself. When we clone an object, it does not matter that the original one is modified, the cloned will be an object a part.
Since the constructor used to create the clone is private, and since it is never modified by the function itself, it does not matter how many times we reassign its prototype, since the only important thing is when we create an instance with new keyword. That instance wont loose its inherited methods or properties.
As example:
As I said, when variable a is created, it inherits everything from A.prototype and, of course, if A.prototype inherits from another constructor, the chain is respected and classic inheritance emulated. Using the unique function inside that closure, we are doing something like this:
In my opinion there aren't side effect but only performances and memory consumption improvements for every browser.
I do not know why I did not think about this way to recycle that function before, but for sure I will never use a new intermediate constructor again, unless somebody will post valid reasons to do it.
Finally, if everybody knew about this tricky way to recycle the constructor, I am sorry, I am late.
MyExtendedConstructor.prototype = function(Function){
var callee = arguments.callee;
if(!(this instanceof callee)){
callee.prototype = Function.prototype;
return new callee;
}
}(MyBaseConstructor);
Above code uses the closure itself to create the intermediate constructor.
The reason i chose this way to operate that task was: why should I use another function when I already have one that is the closure itself?
Well done, one function instead of two ... but wait a second, why should I create a different function everytime instead of recycle a single one?
Douglas Crockford begetObject concept
In one of His historical posts, Big Douglas describes simple JavaScript inheritance and object cloning using an intermediate constructor. This is the Object.create function:
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
Above snippets is still used in I do not know how many JavaScript libraries or code over the net, to extends constructor prototypes or to create a clone of a generic object.
The snippet is clever, powerful, "perfect" for its purpose, but it creates many functions for each object and your JS engine, as your RAM, has not shields to prevent its aggressiveness when you use thousands of times that snippet.
This is a benchmark function example:
function bench(create){
for(var original = {test:"test"}, o = create(original), i = 0, time = new Date; i < 500000; i++)
o = create(o);
return new Date - time;
};
If we test above function with Douglas Object.create one, the result will be something like:
FireFox 3.0.3 - Intel Core2 6600 @ 2.40 - 2GB DDR2 RAM
------------------------------------------------------
Memory: 121.676 Kb
CPU: 50% (not responding)
Elapsed time: 1769 ms
Object.create revisited version
Next snippet is my revisited version of that function:
Object.create = function(Function){
// WebReflection Revision
return function(Object){
Function.prototype = Object;
return new Function;
}}(function(){});
these are advantages about recycling the function:
- memory should not be increased, the function is one
- execution speed should be faster, no functions created for each call
-
apparently,not a single behaviour different from the good old snippet
While these are results with the same configuration:
FireFox 3.0.3 - Intel Core2 6600 @ 2.40 - 2GB DDR2 RAM
------------------------------------------------------
Memory: 37.332 Kb
CPU: 35% (responding)
Elapsed time: 855 ms
Seems to be quite impressive, isn't it? Results are tremendously different with Internet Explorer, where the good old way lets the browser ask if it is the case to stop the script: thousands of milliseconds against approximately 1200 with my revision.
Not only to clone
I tested my revision to extend constructors as well, and everything seems to be absolutely fine. This is the function, based on the precedent one:
Function.extend = function(A, B){
A.prototype = Object.create(B.prototype);
A.prototype.constructor = A;
};
// Usage Example
Function.extend(MyExtendedConstructor, MyConstructor);
Why does it work?
Everything is about the clone strategy itself. When we clone an object, it does not matter that the original one is modified, the cloned will be an object a part.
Since the constructor used to create the clone is private, and since it is never modified by the function itself, it does not matter how many times we reassign its prototype, since the only important thing is when we create an instance with new keyword. That instance wont loose its inherited methods or properties.
As example:
function A(){};
A.prototype = {sayHello:function(){alert("Hello")}};
var a = new A;
// prototype redefinition
A.prototype = {};
alert(a instanceof A); // FALSE
a.sayHello(); // Hello
As I said, when variable a is created, it inherits everything from A.prototype and, of course, if A.prototype inherits from another constructor, the chain is respected and classic inheritance emulated. Using the unique function inside that closure, we are doing something like this:
function A(){}; // generic constructor
function Intermediate(){}; // intermediate function
Intermediate.prototype = {sayHello:function(){alert("Hello")}};
// assign the prototype creating an instance
// the instance does not loose its methods
// inherited during its constructor
A.prototype = new Intermediate;
var a = new A;
// we are changing the constructor prototype
// but A.prototype is an instance of the precedent one
Intermediate.prototype = {};
// the method is still there
a.sayHello();
// the prototype has not been changed
// when created it inherited precedent
// methods or variables
var b = new A;
b.sayHello();
Conclusion
In my opinion there aren't side effect but only performances and memory consumption improvements for every browser.
I do not know why I did not think about this way to recycle that function before, but for sure I will never use a new intermediate constructor again, unless somebody will post valid reasons to do it.
Finally, if everybody knew about this tricky way to recycle the constructor, I am sorry, I am late.
a new Relator object plus unshared private variables
This is a Robert Nyman's post dedicated reply, about JavaScript inheritance and alternatives and private variables.
First of all, I would like to say thanks to Robert for both interesting articles He is writing about JS inheritance, and a link to a personal comment which aim was to bring there my "old" documentation about classical JavaScript inheritance and usage of prototype, closures, and public, privileged, or private, scope when we create a constructor.
Last Rob's post talk about private variables, describing them as shared, if present outside the constructor, and valid only for singleton instances.
This is true, and could cause a lot of headache if we are not truly understanding closures and prototype shared methods behaviour, but there is a way to use this peculiarity about shared private variables to create dedicated private variables.
Before I will write about it, let's look into a generic shared private variable example:
Above example shows that if a variable is created outside the constructor and prototype shared methods use that variable, every call to one of those method from a generic instance will modify that single private variable, created once inside that closure. To obtain a private variable we need privileged methods:
As discussed before in my doc, in robert's posts, and everywhere else in the web, privileged methods create many functions for each instance, and with big projects this is not good for both memory and CPU usage.
The Relator is an object capable to relate a generic variable with a clear object, without modifying the original variable.
The classic example is this:
Since with Relator it is possible to create a unique relation between a generic object and a private Object, it was natural for me to think that a private variable could be a Relator like object using this as unique relationship.
The new version of my Relator still respect the precedent API, being a Relator itself, but is now able to return a new object Relator like that could be used, as example, inside a closure.
The good part of Relator is that the stored variable, if it is an object, is stored by reference, and we can assign more than a private unique relationship between a single object and our extra informations.
The same pattern could be easily re-adapted to create a shared private variables:
Sometime a limitation could be easily managed to obtain desired result.
In this case, thanks to JavaScript closures and its prototype nature, the shared variable become a sort of bridge to obtain private variables for each instance.
It is important to understand that even if we extend the base constructor, every new instance will still persist into original _private variable, inside the Person scope, unless we do not specify a different one, redefining every method that use that variable as well:
See you soon ;)
First of all, I would like to say thanks to Robert for both interesting articles He is writing about JS inheritance, and a link to a personal comment which aim was to bring there my "old" documentation about classical JavaScript inheritance and usage of prototype, closures, and public, privileged, or private, scope when we create a constructor.
About
Last Rob's post talk about private variables, describing them as shared, if present outside the constructor, and valid only for singleton instances.
This is true, and could cause a lot of headache if we are not truly understanding closures and prototype shared methods behaviour, but there is a way to use this peculiarity about shared private variables to create dedicated private variables.
Before I will write about it, let's look into a generic shared private variable example:
Click = function(){
// closure for private methods / variables
// private shared variable
var _total = 0;
// returned constructor + prototype
function Click(){};
Click.prototype.add = function(){
_total++;
};
Click.prototype.getTotal = function(){
return _total;
};
return Click
}();
var left = new Click,
right = new Click;
left.add();
alert(right.getTotal()); // 1
Above example shows that if a variable is created outside the constructor and prototype shared methods use that variable, every call to one of those method from a generic instance will modify that single private variable, created once inside that closure. To obtain a private variable we need privileged methods:
Click = function(){ // privileged methods
var _total = 0;
this.add = function(){
_total++;
};
this.getTotal = function(){
return _total;
};
};
var left = new Click,
right = new Click;
left.add();
alert(right.getTotal()); // 0
As discussed before in my doc, in robert's posts, and everywhere else in the web, privileged methods create many functions for each instance, and with big projects this is not good for both memory and CPU usage.
new Relator object and unshared private variables
The Relator is an object capable to relate a generic variable with a clear object, without modifying the original variable.
The classic example is this:
var myNum = 123;
Relator.set(myNum).description = "I am number 123";
alert(myNum.description); // undefined
alert(Relator.get(myNum).description); // "I am number 123"
Since with Relator it is possible to create a unique relation between a generic object and a private Object, it was natural for me to think that a private variable could be a Relator like object using this as unique relationship.
The new version of my Relator still respect the precedent API, being a Relator itself, but is now able to return a new object Relator like that could be used, as example, inside a closure.
// new Relator can create a Relator like object with method "$"
PrivateRelator = function(Relator){
// Relator argument is a new Relator like object
// present only in this scope
return {
get:function(what){
var value = Relator.get(what);
return value && value.value;
},
set:function(what, value){
Relator.set(what).value = value;
}
}
}(Relator.$()); // create a new Relator
Relator.set(window).value = "Hello World";
Relator.get(window).value; // Hello world
PrivateRelator.get(window); // undefined
PrivateRelator.set(window, "Hello Private World");
PrivateRelator.get(window); // Hello Private World
Relator.get(window).value; // Hello World
The good part of Relator is that the stored variable, if it is an object, is stored by reference, and we can assign more than a private unique relationship between a single object and our extra informations.
The same pattern could be easily re-adapted to create a shared private variables:
Person = function(){
// private methods
function _getName(){
return _private.get(this).name
};
function _setName(name){
_private.get(this).name = name;
};
// private variable, shared by every function in this scope
var _private = Relator.$();
// constructor + prototype
function Person(){
// bridge to _private shared variable
_private.set(this);
};
Person.prototype.getName = function(){
return _getName.call(this);
};
Person.prototype.setName = function(name){
_setName.call(this, name);
};
return Person;
}();
// extended constructor
function Enhanced(){
// necessary to save
// this instance into _private variable
// accessible only via Person scope
Person.call(this);
};
(function(){ // quick runtime extend
var callee = arguments.callee;
if(this instanceof callee)return;
callee.prototype = Person.prototype;
Enhanced.prototype = new callee;
})();
var me = new Person(),
rob = new Enhanced();
me.setName("Andrea");
rob.setName("Robert");
alert([me.getName(), rob.getName()]);
// Andrea,Robert
Conclusion
Sometime a limitation could be easily managed to obtain desired result.
In this case, thanks to JavaScript closures and its prototype nature, the shared variable become a sort of bridge to obtain private variables for each instance.
It is important to understand that even if we extend the base constructor, every new instance will still persist into original _private variable, inside the Person scope, unless we do not specify a different one, redefining every method that use that variable as well:
(function(_private){
Enhanced = function(){
_private.set(this);
};
(function(){ // quick runtime extend
var callee = arguments.callee;
if(this instanceof callee)return;
callee.prototype = Person.prototype;
Enhanced.prototype = new callee;
})();
Enhanced.prototype.getName = function(){
return _private.get(this).name
};
Enhanced.prototype.setName = function(name){
_private.get(this).name = name;
};
})(Relator.$());
See you soon ;)
Wednesday, October 08, 2008
JavaScript bits and bops :-)
This post is about a couple of probably useful JavaScript functions, that on daily basis could make our code smarter ;)
Ok, ok, a prototype into a native constructor is not a good start point, but this one, strings dedicated, is probably one of those "must have" protos, a Replace with multiple inputs, as is for PHP.
With above prototype it is possible to search and replace with multiple RegExps and multiple replacements. The proto works as native replace one, but it is possible to perform a replace like this as well:
Tricky enough?
Sometime we need two arguments for a generic callback, but sometime we need to do something between the first argument and the second one.
A common generic example could be a time based callback, where we need to get a start time, to perform an operation, and then an end time.
With a simple pattern like this one:
We are able to execute a couple of interesting operations.
A timing example is this one:
Can you imagine better applications?
P.S. It's long time I do not post guys, sorry but it's really a busy period :)
String.prototype.Replace
Ok, ok, a prototype into a native constructor is not a good start point, but this one, strings dedicated, is probably one of those "must have" protos, a Replace with multiple inputs, as is for PHP.
String.prototype.Replace = function(replace){return function(RegExp, String){
if(!(RegExp instanceof Array))
RegExp = [RegExp];
if(!(String instanceof Array))
String = [String];
for(var result = this, i = 0, l = 0, index = RegExp.length, length = String.length; i < index; i++)
result = replace.call(result, RegExp[i], String[l < length ? l++ : l - 1]);
return result;
}}(String.prototype.replace);
With above prototype it is possible to search and replace with multiple RegExps and multiple replacements. The proto works as native replace one, but it is possible to perform a replace like this as well:
"abc".Replace([/a/, /b/, /c/], "d"); // ddd
"abc".Replace([/a/, /b/, /c/], ["c", "a", "b"]); // cab
"abc".Replace([/a/, /b/, /c/], ["d", function(){return "e"}]); // dee
Tricky enough?
A meanwhile function pattern
Sometime we need two arguments for a generic callback, but sometime we need to do something between the first argument and the second one.
A common generic example could be a time based callback, where we need to get a start time, to perform an operation, and then an end time.
With a simple pattern like this one:
function meanWhile(before, after){
if(2 < arguments.length)
after = arguments[arguments.length - 1];
// do stuff ... return other stuff
return after - before;
};
We are able to execute a couple of interesting operations.
A timing example is this one:
function bigLoop(){
for(var i = 0, max = arguments[0] || 1000000; i < max; i++);
};
meanWhile(new Date, bigLoop(), new Date); // 180 or less if your PC is faster
meanWhile(new Date, bigLoop(), bigLoop(), new Date); // 360 or less ...
Can you imagine better applications?
P.S. It's long time I do not post guys, sorry but it's really a busy period :)
Subscribe to:
Posts (Atom)