Showing posts with label DOM. Show all posts
Showing posts with label DOM. Show all posts

Friday, January 18, 2008

Next! - Property

Hi, now i am going to present you Next.Property!

In Java a property is for example "int getX()" "setX(int i)" this property is called "x"

In JavaScript 1.6 we have support for getters and setters, so we are able to make x a property that calls a different callback when is accessed, so instead of do "var a=this.getX()" we can do "var a=this.x" and it will internal call a getter funtion tomcalculate and return the value

Its all nice and good but.... Internet Explorer dot support Javascript 1.6, in fact they only support 1.2...

Unfortunately there is no way for a JavaScript library to fix that, well some guy did it but using some dirty VBScript methods, thats not good....

So my idea was to provide some kind of Properties support but since we don't have a way to do it as it should lets extend it a little bit.

So with my code we can't make "var a=this.x;" but we can do:

var this.x.get();
this.x.set(v);
//And the neater one
var anim=this.x.getAnimation(options)
this.x.animate(options)//same as before but automatic starts animating



On "options" we specify "from"( optional: if not specified it uses current value), "to" ("where to animate"), duration (the time it takes), interval ( for make animation smother or less smother )

So its the same options as we pass to a Next.Animation, it actually uses it, so you can do with the returned animation: play, reverse etc...

Now.... How to implement a property? Well, i am posting a simple( and a bit stupid example )


<div id="test" style="border: 1px solid black; background-color: red; width: 100px;">0</div>

<button onclick="anim.play();">play</button>
<button onclick="anim.reverse();">reverse</button>
<button onclick="anim.toggle();">toggle</button>
<button onclick="aprop.animate({from:10,to:150});">use animate directly</button>
<script type="text/javascript">
var a=10;
function get(){
return a;
};
function set(value){
var t=document.getElementById("test");
a=value;
t.innerHTML=a;
t.style.width=a+"px";
}
aprop=Next.Number(null,get,set);
anim=aprop.getAnimation({from:10,to:150});
</script>


At the moment only Next.Number is done.
The first parameter is the object were the functions will be applied, this case is null because we the functions are on global scope, the other 2 parameters is the getter and the setter function.

Ok this may look hard to implement and don't look so nice, you are right!

But this property system can be applied on HTMLElement, since the property need to be registed on the thisObject i decided to extend the HTMLElement.extend so it also create the properties
So we have HTMLElement.props that is an array, you can add objects with property options and they will be automatic applied to HTMLElement whan you use Next.byId, $ or other element functions

So we can do:

HTMLElement.props.push({
name:"marginLeft",
getter:function(){
return this.getStyle("margin-left").toFloat();
},
setter:function(v){
this.setStyle("margin-left:"+v+"px");
}
});
Then you can have:
<div style="background-color: blue;" onclick="$(this).marginLeft.animate({to:200});">click</div>

When you click it will increase the margin-left until 100px;
Of course you can also do $(this).marginLeft.get(); to get the value or $(this).marginLeft.set(v); to set the value of it

I think its a great feature, ease to use, much more things can be added like opacity, width left.....

Next thing i want to add to the animator stuff is "by" so we can do $(this).marginLeft.animate({by:100}); and each onclick it would increase more 100 px to margin-left

I hope everyone enjoyed :)

Next! - getStyle

Hi, we all need sometimes to get the style of one HTMLElement, and most times we do

var a=theelement.style.color;

If there was a "color" rule on the element own style, that will work. But it wont work if the "color" was set on a CSS rule.
So that breaks, for example in PrototypeJS they have $("elid").visible() that should return true if the element is visible, how they check?

element.style.display!="none";

But that will say the object is visible if i set it to display:none on a CSS rule

While working with PrototypeJS i had lots of troubles cause i always had to use style="display:none" or the animation stuff ( Script.aculo.us ) would not work.

This guy http://berniecode.com/writing/animator.html did a fix on the code he use for animate CSS properties, so i adapted it to work on Next!, its cross browser

/**
* Get the value of the style
* Based on http://berniecode.com/writing/animator.html
* @param {String} style
*/
HTMLElement.prototype.getStyle=function(property, def){
def=(def===undefined)?"":def;
if (property=="float" || property=="cssFloat" || property=="propertyFloat"){
property=(this.style.styleFloat)?"styleFloat":"cssFloat";
}
if (property=="opacity" && this.filters){
try{
return this.filters.item("Alpha").opacity/100;
}catch(e){
return 1;
}
}
var style;
if(document.defaultView && document.defaultView.getComputedStyle){
style = document.defaultView.getComputedStyle(this, "").getPropertyValue(property);
if (style) {
return style;
}
}
property = property.camelize();
if(this.currentStyle){
style = this.currentStyle[property];
}
return style || this.style[property];
};

This function itself fix also the "opacity" so in this lib you can not only set the opacity but you can get the opacity of the element even if it is a filter ( IE ) on some CSS rule

This code is need and really moves the library to a next stage, we can get the REAL style of the element not only the in-line style, just great!

Now that we have a getStyle we must also have a setstyle
setStyle its simpler it will just set the inline style of the element

/**
* Set the style of the element
* @param {String|Object} style
* @return {HTMLElement}
*/
HTMLElement.prototype.setStyle=function(style){
if (String.is(style)){
this.style.cssText+=";"+style;
if (style.contains("opacity:")){
this.setOpacity(style.match(/opacity:\s*(\d?\.?\d*)/)[1]);
}
}else if (Object.is(style)){
for (i in style){
if (i == "float" || i == "cssFloat" || i == "styleFloat") {
this.style.cssFloat=style[i];
this.style.styleFloat=style[i];
}else if (i=="opacity"){
this.setOpacity(style[i]);
}else{
this.style[i]=style[i];
}
}
}
return this;
};

This code is still missing a fix, it will be done soon, but the base idea is that you can do
theelement.setStyle("color:red;");
theelement.setStyle({"color":"red"});

More things are comming!!

Tuesday, January 15, 2008

Next! - Element

Hi everyone!

Today i am going to talk about DOM elements and how to extend them


In most modern browsers there are Interfaces for all kind of elements. All them extend the base Interface: HTMLElement. For example a div tag use the interface: HTMLDivElement that extends HTMLElement.

So this mean that we can easily add functions to elements, like this:

HTMLElement.prototype.hide=function(){
    this.style.display="none";
}  

And now we can call that function on any element, for example:

document.getElementById("test").hide();
document.createElement("a").hide();

Nice huh?

Yes it is very nice and may come in handy but theres a problem... the same problem ever... Internet Explorer DON'T support it. Also even HTMLElement don't exist!

So what can we do?

    Next.browserExtensions=true
    if (!window.HTMLElement ){
        window.HTMLElement = function(){};//Empty function
        Next.browserExtensions=false
    }
   
    //now we need to create a helper function to extend the object on unsupported browsers  
    HTMLElement.extend= function(element){
       if (element && !element._extended && !Next.browserExtensions){
          for (var i in HTMLElement.prototype){
              element[i]=HTMLElement.prototype[i];  
           }
       }
       return element;
    };
    //this is a marker, so we dont exten the same object each time we  need it
    HTMLElement.prototype._extended=true

    HTMLElement.prototype.hide=function(){

        this.style.display="none";
    } ;
   
    //now we need a function to get the element and extend it
    Next.byId=function(element){
       return HTMLElement.extend(document.getElementById(element));
    };

    Next.byId("test").hide();//Now it works on all browsers

This implementation is simple and not much heavy and works well.
Others would make everything rely on Object extenders

With some work we could do it able to have different functions for different tag's.

Its all for now! Its time to implement ll this on Next!
The next post i might talk about animation say tuned!

Blogged with Flock