My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label multiple. Show all posts
Showing posts with label multiple. Show all posts

Wednesday, June 10, 2009

Wait A Moment, JavaScript Does Support Multiple Inheritance!

... we are just doing it wrong!

Classical Inheritance? We Have Something Better!

The main limit about multiple inheritance in JavaScript is the presence of "instanceof" operator. In a prototypal based inheritance objects simply inherits from objects, and class keyword is almost meaningless.

// generic constructor
function B(){};

// remember the prototype
var B1proto = B.prototype;

// B instance
var b1 = new B;

// prototype reassignment
B.prototype = {
constructor:B
};

// remember new prototype
var B2proto = B.prototype;

// B instance
var b2 = new B;

alert(b2 instanceof B); // true
alert(b1 instanceof B); // false

Above snippet demonstrates how inheritance and instanceof are related to the current prototype, rather than the function/constructor itself.
In few words, the function is the implicit init method for the current prototype object. The relation, as we could spot with FireFox, is with the prototype and not the used constructor.

// FireFox exposes __proto__
// will be Object.getPrototypeOf
// in ECMAScript 3.1
b1.__proto__ == B1proto; // true
b2.__proto__ == B2proto; // true


Sure, And What About Multiple Inheritance?

... I am going there, wait another few seconds :D
Since the prototype is the relation, and not the constructor, and since a prototype is nothing but a common Object, we can add whatever method or property we want to this prototype object in order to obtain the hybrid one we are looking for.

function A(){};
A.prototype.name = "A instance";
A.prototype.getName = function(){
return this.name;
};

function B(){};
B.prototype.name = "B instance";

function C(){};
// default name from B
C.prototype.name = B.prototype.name;
// getName from A
C.prototype.getName = A.prototype.getName;
// new method for C
C.prototype.setName = function(name){
this.name = name;
};

var c = new C();
c.getName(); // B instance
c.setName("Andrea");
c.getName(); // Andrea

In few words, we can add whatever we want to a prototype object creating exactly what multiple inheritance would create. We still have a problem with instanceof operator, don't we? Well, considering that "instance" concept is something more meaningful in classical inheritance, we could say that it is not possible to emulate multiple inheritance Python like with JavaScript, but we can inject whatever method/property from whatever constructor.prototype, something not possible with Java, PHP, C#, and others ... so are we missing something?

A Basic Object.implement Function Check

Due to the fact we could need to know if an hybrid instance is using this or that method, we could think about an abstract implement method able to tell us if a generic instance constructor prototype, is at least implementing another constructor prototype, considering latter one as an interface. If this is true, we are sure that we can use that instance/object in that way and without problems ... isn't it?

Object.implement = function(o, constructor){
// Another WebReflection Insane Snippet
if(o instanceof constructor)
// nothing to check
// classical boring stuff
return true;
// let's check if things are OK
var k, b = true,
// take the instance constructor prototype
po = o.constructor.prototype,
// take the implemented prototype
pc = constructor.prototype
;
// for each property or method
// in the implemented constructor
for(k in pc)
// check if the instance inherited prototype
// has this method/property as well
b = b && k in po; //* TOTHINK: */ && (typeof po[k] === typeof pc[k]); //*/
// if there was nothing to check
// we cannot say a word ... but ...
// if instance has every method/property
// present in the compared constructor
// prototype, we could say this instance
// implements this constructor
return !!k && b;
};

Purist Classical OOP Developers are probably already rolling around the floor in pain and screaming he's f#@*in idiot, but what is the meaning of implement in classical inheritance patterns?
Wikipedia - Interface

Interfaces are used to encode similarities which classes of various types share, but do not necessarily constitute a class relationship

In few words my latest snippet checks if an object contains every method/property defined in another object so, using first example, we could do:

// add noise and chaos with another constructor ...
function D(){};
D.prototype.notInObject = true;

// check Object.implement ...
Object.implement(c, A); // true
Object.implement(c, B); // true
Object.implement(c, C); // true
Object.implement(c, D); // false


Nothing new? Nothing true? Is it clear for everybody? 8-)

Friday, March 20, 2009

noSWFUpload - Zero Plug-In Multiple Upload

As announced a couple of days ago, I am finally proud to introduce my last library free Multiple Upload Component, now compatible with every browser and always without usage of 3rd parts plug-ins.


This little project has been hosted in Google Code and I promise I'll write there a complete documentation asap. Righ now, you can read the project source code via zip to understand what he little API is doing.

Update I added a couple of sections in the Wiki page ;)

Compatibility?
  • Internet Explorer 5.5 (probably 5 too), 6, 7, and 8
  • FireFox? 3 or greater
  • Google Chrome 1.0
  • Opera 8, 9, and 10
  • Safari 4 (current beta)
  • other browsers via unobtrusive iframe


Try the demo if you do not believe it :P

Sunday, March 15, 2009

Multiple Upload With Progress: Every Browser No Flash !!!

Update: released official version in Google Code, cross browser, and easy to use. blog enry


Ok guys, this is a quick and dirty entry in my blog. I need to write documentation, create the project in Google Code, explain better what I have done and how it works.
I do not want to give you the zip right now because I have to change name (silly me do not check before) and to do last tests ... but basically, what I have created this week end, is a graceful enhanced multiple file upload manager compatible with Chrome, FireFox, Internet Explorer (5.5 or greater), Opera, Safari.



The manager wrap an input type file and manages it allowing multiple files selection, where supported, or one after one insert with possibility to remove one or more file from the list.

Everything is absolutely customizable, since the wrapper is entirely in CSS, the library has a language namespace for errors or messages, and events are created by developers.

In those browsers were Ajax upload is not supported, the progress bar is simulated, but there is the feeling that something is happening.

In FireFox, where Ajax upload is supported, the progress is still simulated but at least the size, sent or total, is real.

Stay tuned for the official announcement, enjoy the demo in my website.

Quick thanks and credit to Silk Icon Set from famfamfam!

P.S. Yes, there is a file type filter as well, Flash like, and I have solved server side $_FILES problem with Safari 4 ... but please wait next blog entry!

Monday, March 09, 2009

Safari 4 Multiple Upload With Progress Bar

Update - I slightly modified the demo page adding another bar, the one for the current file. I'll update the zip asap but all you need is a copy and paste of the JS in the index. Apparently multiple should be set as multiple, rather than true ... in any ... it works as long as it is an attribute.


This one from Ajaxian has been one of the best news I could read about HTML5 specs and browsers evolution.
I could not wait to download Safari 4 and test instantly this feature.
I have always been interested in this possibility, both progress bar, plus multiple uploads and that's why I would like to add this post to this list:


First Step: The Input Type File

We can create a multiple input files in different ways: directly in the layout

<input type="file" multiple="multiple" />

or via JavaScript:

var input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("multiple", "multiple"); // note: input.multiple = "multiple" does not work in Safari 4 beta

I know we all like graceful degradation, but in this post I will only talk about a client side progress bar, something that is cool and possible, so far, only via JavaScript ;-)


Second Step: XMLHttpRequest Version 2

The last implementation of this constructor brings some cool stuff with him, the XMLHttpRequestUpload interface, used by an automatic created property called upload.
The reason this property is as cool as welcome, is that it can trace sent binary data via dispatched events like onload, onprogress, and others.

var xhr = new XMLHttpRequest,
upload = xhr.upload;
upload.onload = function(){
console.log("Data fully sent");
};
xhr.open("post", page, true);
xhr.send(binaryData);

Above snippet is the basis of the new feature introduced by Safari 4, feature better explained in the dedicated example I prepared for this post.


Third Step: The PHP Manager

If we use multiple attribute without XMLHttpRequest, we simply need to set a name, and manage data in the server via the superglobal $_FILES. But if we want to send directly the binary stream, the only thing we need to do in the server, security checks a part, is to save the content sent via input:

<?php
// e.g. url:"page.php?upload=true" as handler property
if(isset($_GET['upload']) && $_GET['upload'] === 'true'){
$headers = getallheaders();
if(
// basic checks
isset(
$headers['Content-Type'],
$headers['Content-Length'],
$headers['X-File-Size'],
$headers['X-File-Name']
) &&
$headers['Content-Type'] === 'multipart/form-data' &&
$headers['Content-Length'] === $headers['X-File-Size']
){
// create the object and assign property
$file = new stdClass;
$file->name = basename($headers['X-File-Name']);
$file->size = $headers['X-File-Size'];
$file->content = file_get_contents("php://input");

// if everything is ok, save the file somewhere
if(file_put_contents('files/'.$file->name, $file->content))
exit('OK');
}

// if there is an error this will be the output instead of "OK"
exit('Error');
}
?>



Last Step: The Client Manager With The Progress Bar

This is the last thing we should care about, and only after we are sure we implemented best security checks to avoid problems for users and the server itself. In this example I did not implement too many checks, so please take it as a hint, rather than a final solution for public production environments.
The client side is really simple and entirely managed via JavaScript.

/** basic Safari 4 multiple upload example
* @author Andrea Giammarchi
* @blog WebReflection [webreflection.blogspot.com]
*/
onload = function(){

function size(bytes){ // simple function to show a friendly size
var i = 0;
while(1023 < bytes){
bytes /= 1024;
++i;
};
return i ? bytes.toFixed(2) + ["", " Kb", " Mb", " Gb", " Tb"][i] : bytes + " bytes";
};

// create elements
var input = document.body.appendChild(document.createElement("input")),
bar = document.body.appendChild(document.createElement("div")).appendChild(document.createElement("span")),
div = document.body.appendChild(document.createElement("div"));

// set input type as file
input.setAttribute("type", "file");

// enable multiple selection (note: it does not work with direct input.multiple = true assignment)
input.setAttribute("multiple", "multiple");

// auto upload on files change
input.addEventListener("change", function(){

// disable the input
input.setAttribute("disabled", "true");

sendMultipleFiles({

// list of files to upload
files:input.files,

// clear the container
onloadstart:function(){
div.innerHTML = "Init upload ... ";
bar.style.width = "0px";
},

// do something during upload ...
onprogress:function(rpe){
div.innerHTML = [
"Uploading: " + this.file.fileName,
"Sent: " + size(rpe.loaded) + " of " + size(rpe.total),
"Total Sent: " + size(this.sent + rpe.loaded) + " of " + size(this.total)
].join("<br />");
bar.style.width = (((this.sent + rpe.loaded) * 200 / this.total) >> 0) + "px";
},

// fired when last file has been uploaded
onload:function(rpe, xhr){
div.innerHTML += ["",
"Server Response: " + xhr.responseText
].join("<br />");
bar.style.width = "200px";

// enable the input again
input.removeAttribute("disabled");
},

// if something is wrong ... (from native instance or because of size)
onerror:function(){
div.innerHTML = "The file " + this.file.fileName + " is too big [" + size(this.file.fileSize) + "]";

// enable the input again
input.removeAttribute("disabled");
}
});
}, false);

bar.parentNode.id = "progress";

};

The external file with sendFile and sendMultipleFile function is in my repository and in the attached zip, while a workable example page with a limit of 1Mb for each file is here in my host.

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 ;)

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 :)