...

View Full Version : Chaining function calls jQuery style



mattyod
07-26-2010, 04:48 PM
Hi, I've been playing around trying to recreate the way in which jQuery chains it's functions for it's "select" then "do" behaviour.

Note: I don't want to chain functions with jQuery, I want to chain them like jQuery.

So based on the jQuery code what I have so far is (doesn't work in IE):



var x = function(string) {
return new x.fn.init(string);
};

x.fn = x.prototype = {

message: '',

init: function(string) {
x.fn.message = string;
},

log: function() {
console.log(x.fn.message);
}
};

x.fn.init.prototype = x.fn;

var start = function() {
x('hello world').log();
};

document.addEventListener('DOMContentLoaded', start, false);


The code works but when I watch '$' in jQuery "fn" & "prototype" show up as being "jQuery()" but in my code when I watch "x": "fn" and "prototype" are both shown as objects containing "message", "init" and "log" and in both cases "init" contains "prototype" which contains my three functions again and the nesting continues seemingly infinitely...

I'm clearly missing something here. What are they doing in differently in jQuery to prevent this endless nesting loop?

TinyScript
07-27-2010, 10:08 PM
I played with your code a little. Not sure if this helped or hurt.



<script>
var x = function(id){
return new x.fn.init(id)
}

x.fn = {
init : function(string) {
x.fn.id = string;
x.fn.elm=document.getElementById(x.fn.id)
},
mouseover : function(fn){
return x.fn.elm.onmouseover=fn
},
mouseout : function(fn){
return x.fn.elm.onmouseout=fn
},

html : function(html){
x.fn.elm.innerHTML = html
},
append : function(html){
x.fn.elm.innerHTML += html
},
css : function(style){
x.fn.elm.style.cssText=style
},
font : function(font){
x.fn.elm.style.font=font
},
color : function(color){
x.fn.elm.style.color=color
}
};


x.fn.init.prototype = x.fn;


var start = function() {

x("world").color("green")
x("world").html("hello world")

x("world2").color("red")
x("world2").font("16px arial black")
x("world2").html("hello2")
x("world2").append("<br>more text")


x("world3").css("font:16px arial black;color:orange;background-color:black")
x("world3").html("hello3")
x("world3").mouseover(function(){x("world3").html("mouse over")})
x("world3").mouseout(function(){x("world3").html("hello3")})
};

window.onload= start;

</script>
<div id="world"></div><br>
<div id="world2"></div>
<div id="world3"></div>

mattyod
07-28-2010, 12:58 PM
Erm you've extended it into the beginnings of your own js library rather than dealing with the question but never mind :)

Actually on further investigation I've noted that the watch on "$" of jquery also allows you to go into an infinite loop of nesting via "fn" or "prototype".

I'm guessing this isn't a bad thing and just indicates the self reference pointing.

If it's good enough for John it's good enough for me :cool:

TinyScript
07-30-2010, 05:54 PM
Well, I wasn't able to answer your question until I figured it out myself. LOL

I used p01's method of chaining.
http://www.p01.org/releases/20_lines_hypno_trip_down_the_fractal_rug/

It doesn't work with my move function, but you can chain the other functions.



<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
/*fauxQuery*/
var faux = function () {}
faux.prototype = {
init: function (id) {
this.id = id;
this.elm = document.getElementById(this.id)
},
over: function (fn) {
return this.elm.onmouseover = fn
},
out: function (fn) {
return this.elm.onmouseout = fn
},
down: function (fn) {
return this.elm.onmousedown = fn
},

move: function (prop, endVal, steps, speed, N) {
var self = this
self.timer = null
self.currVal = parseInt(this.elm.style[prop])
self.ease = function (currVal, endVal, steps, incr, N) {
return currVal + Math.pow(incr / steps, N) * (endVal - currVal)
}
clearInterval(self.timer);
var incr = 0;
self.timer = setInterval(function () {
self.elm.style[prop] = Math.round(self.ease(self.currVal, endVal, steps, incr, N)) + "px"
incr++;
if (incr > steps) {
self.elm.style[prop] = endVal + "px";
clearInterval(self.timer)
}
}, speed)
},
fade: function (endVal, steps, speed, N) {
var self = this
self.timer = null
self.currVal = !self.elm.style.opacity ? parseFloat(self.elm.style.filter) : parseFloat(self.elm.style.opacity)
self.ease = function (currVal, endVal, steps, incr, N) {
return currVal + Math.pow(incr / steps, N) * (endVal - currVal)
}
clearInterval(self.timer);
var incr = 0;
self.timer = setInterval(function () {
self.elm.style.opacity = self.ease(self.currVal, endVal, steps, incr, N);
self.elm.style.filter = "alpha(opacity=" + (self.ease(self.currVal, endVal, steps, incr, N) * 100) + ")";
incr++;
if (incr > steps) {
self.elm.style.opacity = endVal;
self.elm.style.filter = "alpha(opacity=" + (endVal * 100) + ")";
clearInterval(self.timer)
}
}, speed)
},
tag: function (tag, n) {
var A = !n ? this.elm.getElementsByTagName(tag) : this.elm.getElementsByTagName(tag)[n]
return A
},
clsn: function (cn, n) {
function byClassN(Elm, cname) {
var A = [];

function classN(elm, cn) {
return elm.attributes.getNamedItem("class").nodeValue == cn
}
var i = 0;
while (Elm.children[i]) {
var E = Elm.children[i];
if (classN(E, cname)) {
A.push(E)
};
i++
}
return A
}
if (!this.elm.getElementsByClassName) {
return !n ? byClassN(this.elm, cn) : byClassN(this.elm, cn)[n];
} else {
var A = !n ? this.elm.getElementsByClassName(cn) : this.elm.getElementsByClassName(cn)[n];
return A
}
},
html: function (html) {
this.elm.innerHTML = html
},
append: function (html) {
this.elm.innerHTML += html
},
css: function (style) {
this.elm.style.cssText = style
},
font: function (font) {
this.elm.style.font = font
},
color: function (color) {
this.elm.style.color = color
}
};
function $faux(func){return function(){ return func.apply( this, arguments ) || this }}
for( fn in faux.prototype){ faux.prototype.init.prototype[fn] = $faux( faux.prototype[fn] )}
var id = function (id) {


var $= new faux.prototype.init(id)

return $
}
var start = function () {

id("world").color("green").html("hello world").css("font:16px arial black;width:200px;height:30px;background-color:gray")

id("world2").color("red").font("16px arial black").html("hello2").append("<br>more text<div class='change'></div>")
id("world3").css("font:16px arial black;position:absolute;left:200px;top:200px;width:200px;height:70px;color:orange;background-color:black")
id("world3").html("Example 3")
id("world3").over(function () {
id("world3").html("Click for instructions").color("red");
id("world3").fade(.5, 50, 5, 2)
})
id("world3").out(function () {
id("world3").html("Example 3").color("orange")
id("world3").move("width", 200, 50, 5, 2)
id("world3").move("height", 70, 50, 5, 2)
id("world3").move("left", 200, 50, 5, 4)
id("world3").move("top", 200, 50, 5, 4)
id("world3").fade(1, 50, 5, 2)
})
id("world3").elm.onmousedown = function () {
id("world3").move("width", 400, 50, 5, 4)
id("world3").move("height", 400, 50, 5, 4)
id("world3").move("left", 10, 50, 5, 4)
id("world3").move("top", 10, 50, 5, 4)
id("world3").fade(1, 50, 5, 2).color("green")
}
id("world3").fade(0, 1, 5, 2)
setTimeout(' id("world3").fade(1, 50, 5, 2)', 6500)
setTimeout('id("world4").tag("div")[0].innerHTML="tag fn works"', 1500)
setTimeout(function () {
id("world4").clsn("change")[0].innerHTML += "<br>class fn works"
}, 3500)
setTimeout(function () {
id("world4").tag("div", "0").innerHTML += "<br>tag fn works"
}, 4500)
setTimeout(function () {
id("world4").clsn("change", "0").innerHTML += "<br>class fn works"
}, 5500)
setTimeout(function () {
id(id("world5").clsn("change")[0].id).css("color:green;font:18px arial black");
id(id("world5").clsn("change")[1].id).down(function () {
this.innerHTML = "clicked";
this.onmouseout = function () {
this.innerHTML = "click me "
}
})
}, 200)
};
window.onload = start
</script>
<div id="world"></div><br>
<div id="world2"></div>
<div id="world3"></div>
<div id="world4"></div>
<div id="world5">div 5 <br><div id="blah" class="change">click</div><div id="blah2" class="change">click2</div></div>



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum