Commit 75b9d744 authored by Addy Osmani's avatar Addy Osmani

Bringing back in JavaScriptMVC implementation based on #252. Note: we need to...

Bringing back in JavaScriptMVC implementation based on #252. Note: we need to reduce JMVC dep. bloat.
parent 70fa853c
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
<a href="labs/architecture-examples/montage/" data-source="https://github.com/Motorola-Mobility/montage" data-content="Montage simplifies the development of rich HTML5 applications by providing modular components, real-time two-way data binding, CommonJS dependency management, and many more conveniences.">Montage</a> <a href="labs/architecture-examples/montage/" data-source="https://github.com/Motorola-Mobility/montage" data-content="Montage simplifies the development of rich HTML5 applications by providing modular components, real-time two-way data binding, CommonJS dependency management, and many more conveniences.">Montage</a>
</li> </li>
<li class="labs"> <li class="labs">
<a href="https://github.com/addyosmani/todomvc/tree/gh-pages/labs/architecture-examples/canjs#canjs-and-javascriptmvc" data-source="http://javascriptmvc.com" data-content="JavaScriptMVC is an open-source framework containing the best ideas in jQuery development. It guides you to successfully completed projects by promoting best practices, maintainability, and convention over configuration.">JavaScriptMVC</a> <a href="labs/architecture-examples/javascriptmvc/todo" data-source="http://javascriptmvc.com" data-content="JavaScriptMVC is an open-source framework containing the best ideas in jQuery development. It guides you to successfully completed projects by promoting best practices, maintainability, and convention over configuration.">JavaScriptMVC</a>
</li> </li>
<li class="labs"> <li class="labs">
<a href="labs/architecture-examples/extjs/" data-source="http://www.sencha.com/products/extjs" data-content="Ext JS 4 is the next major advancement in our JavaScript framework. Featuring expanded functionality, plugin-free charting, and a new MVC architecture it's the best Ext JS yet. Create incredible web apps for every browser.">Ext.js</a> <a href="labs/architecture-examples/extjs/" data-source="http://www.sencha.com/products/extjs" data-content="Ext JS 4 is the next major advancement in our JavaScript framework. Featuring expanded functionality, plugin-free charting, and a new MVC architecture it's the best Ext JS yet. Create incredible web apps for every browser.">Ext.js</a>
......
TOC:
A. How to get (and contribute) to JMVC
A. How to get (and contribute) JMVC
1. Start a new project in git.
2. Fork ....
http://github.com/jupiterjs/steal and
http://github.com/jupiterjs/jquerymx
3. Add steal and jquerymx as submodules of your project...
git submodule add git@github.com:_YOU_/steal.git steal
git submodule add git@github.com:_YOU_/jquerymx.git jquery
* Notice jquerymx is under the jquery folder
4. Learn a little more about submodules ...
http://johnleach.co.uk/words/archives/2008/10/12/323/git-submodules-in-n-easy-steps
5. Make changes in steal or jquerymx, and push them back to your fork.
6. Make a pull request to your fork.
// load('jquery/build.js')
load('steal/rhino/rhino.js')
var i, fileName, cmd,
plugins = [
"class" ,
"controller",
{
plugin: "controller/subscribe",
exclude: ["jquery/controller/controller.js",
"jquery/class/class.js",
"jquery/lang/lang.js",
"jquery/event/destroyed/destroyed.js",
"jquery/controller/controller.js"]},
"event/default",
"event/destroyed",
"event/drag",
"event/pause",
"event/resize",
{
plugin: "event/drag/limit",
exclude: ["jquery/lang/vector/vector.js", "jquery/event/livehack/livehack.js", "jquery/event/drag/drag.js"]},
{
plugin: "event/drag/scroll",
exclude: ["jquery/dom/within/within.js", "jquery/dom/compare/compare.js", "jquery/event/drop/drop.js","jquery/lang/vector/vector.js", "jquery/event/livehack/livehack.js", "jquery/event/drag/drag.js"]},
{
plugin: "event/drop",
exclude: ["jquery/lang/vector/vector.js", "jquery/event/livehack/livehack.js", "jquery/event/drag/drag.js"]},
"event/hover",
"view/ejs",
"dom/closest",
"dom/compare",
{
plugin: "dom/dimensions",
fileName: "jquery.dimensions.etc.js"
},
"dom/fixture",
"dom/form_params",
"dom/within",
"dom/cur_styles",
"model",
{
plugin: "model/backup",
exclude: ["jquery/class/class.js",
"jquery/lang/lang.js",
"jquery/event/destroyed/destroyed.js",
"jquery/lang/openajax/openajax.js",
"jquery/model/model.js"]
},
{
plugin: "model/list",
exclude: ["jquery/class/class.js",
"jquery/lang/lang.js",
"jquery/event/destroyed/destroyed.js",
"jquery/lang/openajax/openajax.js",
"jquery/model/model.js"]
},
{
plugin: "model/list/cookie",
exclude: ["jquery/class/class.js",
"jquery/lang/lang.js",
"jquery/event/destroyed/destroyed.js",
"jquery/lang/openajax/openajax.js",
"jquery/model/model.js",
"jquery/model/list/list.js"]
},
{
plugin: "model/list/local",
exclude: ["jquery/class/class.js",
"jquery/lang/lang.js",
"jquery/event/destroyed/destroyed.js",
"jquery/lang/openajax/openajax.js",
"jquery/model/model.js",
"jquery/model/list/list.js"]
},
{
plugin: "model/validations",
exclude: ["jquery/class/class.js",
"jquery/lang/lang.js",
"jquery/event/destroyed/destroyed.js",
"jquery/lang/openajax/openajax.js",
"jquery/model/model.js"]
},
"view",
"view/ejs",
"view/jaml",
"view/micro",
"view/tmpl"
]
steal.File('jquery/dist').mkdir();
steal('steal/build/pluginify').then( function(s){
var plugin, exclude, fileDest, fileName;
for(i=0; i<plugins.length; i++){
plugin = plugins[i];
exclude = [];
fileName = null;
if (typeof plugin != "string") {
fileName = plugin.fileName;
exclude = plugin.exclude || [];
plugin = plugin.plugin;
}
fileName = fileName || "jquery."+plugin.replace(/\//g, ".").replace(/dom\./, "").replace(/\_/, "")+".js";
fileDest = "jquery/dist/"+fileName
s.build.pluginify("jquery/"+plugin,{
nojquery: true,
out: fileDest,
exclude: exclude.length? exclude: false
})
var outBaos = new java.io.ByteArrayOutputStream();
var output = new java.io.PrintStream(outBaos);
runCommand("java", "-jar", "steal/build/scripts/compiler.jar", "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--js", fileDest, {
output: output
});
var minFileDest = fileDest.replace(".js", ".min.js")
new steal.File(minFileDest).save(outBaos.toString());
}
})
/*
for (i = 0; i < plugins.length; i++) {
plugin = plugins[i];
exclude = [];
fileName = null;
if (typeof plugin != "string") {
fileName = plugin.fileName;
exclude = plugin.exclude || [];
plugin = plugin.plugin;
}
fileName = fileName || "jquery." + plugin.replace(/\//g, ".").replace(/dom\./, "").replace(/\_/, "") + ".js";
fileDest = "jquery/dist/" + fileName
// compress
var outBaos = new java.io.ByteArrayOutputStream();
var output = new java.io.PrintStream(outBaos);
runCommand("java", "-jar", "steal/build/scripts/compiler.jar", "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--warning_level", "QUIET", "--js", fileDest, {
output: output
});
var minFileDest = fileDest.replace(".js", ".min.js")
new steal.File(minFileDest).save(outBaos.toString());
print("***" + fileName + " pluginified and compressed")
}*/
// load('jquery/buildAll.js')
load('steal/rhino/rhino.js')
// load every plugin in a single app
// get dependency graph
// generate single script
steal('steal/build/pluginify','steal/build/apps','steal/build/scripts').then( function(s){
var ignore = /\.\w+|test|generate|dist|qunit|fixtures|pages/
var plugins = [],
/**
* {"path/to/file.js" : ["file2/thing.js", ...]}
*/
files = {};
s.File('jquery').contents(function( name, type, current ) {
if (type !== 'file' && !ignore.test(name)) {
var folder = current+"/"+name;
if(readFile(folder+"/"+name+".js")){
print(folder);
plugins.push(folder);
steal.File(folder).contents(arguments.callee, folder)
}
//steal.File(path + "/" + (current ? current + "/" : "") + name).contents(arguments.callee, (current ? current + "/" : "") + name);
}
},"jquery");
// tell it to load all plugins into this page
//steal.win().build_in_progress = true;
print(" LOADING APP ")
steal.build.open('steal/rhino/blank.html', {
startFiles: plugins
}, function(opener){
opener.each('js', function(options, text, stl){
print(options.rootSrc)
var dependencies = files[options.rootSrc] = [];
if(stl.dependencies){
for (var d = 0; d < stl.dependencies.length; d++) {
var depend = stl.dependencies[d];
if (depend.options.rootSrc !== "jquery/jquery.js") {
dependencies.push(depend.options.rootSrc);
}
}
}
})
s.File("jquery/dist/standalone").mkdirs();
s.File("jquery/dist/standalone/dependencies.json").save($.toJSON(files));
//get each file ...
print("Creating jquery/dist/standalone/")
var compressor = s.build.builders.scripts.compressors[ "localClosure"]()
for(var path in files){
if(path == "jquery/jquery.js"){
continue;
}
var content = readFile(path);
var funcContent = s.build.pluginify.getFunction(content);
if(typeof funcContent == "undefined"){
content = "";
} else {
content = "("+s.build.pluginify.getFunction(content)+")(jQuery);";
}
var out = path.replace(/\/\w+\.js/,"").replace(/\//g,".");
content = s.build.builders.scripts.clean(content);
print(" "+out+"");
content = s.build.builders.scripts.clean(content);
s.File("jquery/dist/standalone/"+out+".js").save(content);
s.File("jquery/dist/standalone/"+out+".min.js").save(compressor(content));
}
})
/*
var pageSteal = steal.build.open("steal/rhino/empty.html").steal,
steals = pageSteal.total,
files = {},
depends = function(stl, steals){
if(stl.dependencies){
for (var d = 0; d < stl.dependencies.length; d++) {
var depend = stl.dependencies[d];
if(!steals[depend.path]){
steals[depend.path] = true;
print("123 " + depend.path);
//depends(depend, steals);
}
}
}
},
all = function(c){
for(var i =0; i < steals.length; i++){
var pSteal =steals[i];
if(!pSteal.func){
c(pSteal)
}
}
};
print(" LOADED, GETTING DEPENDS");
all(function(stl){
files[stl.path] = stl;
})
all(function(stl){
print(stl.path)
var dependencies = files[stl.path] = [];
if(stl.dependencies){
for (var d = 0; d < stl.dependencies.length; d++) {
var depend = stl.dependencies[d];
if (depend.path !== "jquery/jquery.js") {
dependencies.push(depend.path);
}
}
}
})*/
})
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>jQuery.Class Demo</title>
<style type='text/css'>
body {font-family: verdana}
.tabs, .history_tabs {
padding: 0px; margin: 20px 0 0 0;
}
li {
float: left;
padding: 10px;
background-color: #F6F6F6;
list-style: none;
margin-left: 10px;
}
li a {
color: #1C94C4;
font-weight: bold;
text-decoration: none;
}
li.active a {
color: #F6A828;
cursor: default;
}
.tab {
border: solid 1px #F6A828;
}
/* clearfix from jQueryUI */
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
</style>
</head>
<body>
<p>jQuery.Class Demo shows a tabs controller extended to work with history.</p>
<div id="demo-html">
<h2>Basic Tabs</h2>
<ul id='tabs1' class='ui-helper-clearfix''>
<li><a href='#tab1'>Tab 1</a></li>
<li><a href='#tab2'>Tab 2</a></li>
<li><a href='#tab3'>Tab 3</a></li>
</ul>
<div id='tab1' class='tab'>Tab 1 Content</div>
<div id='tab2' class='tab'>Tab 2 Content</div>
<div id='tab3' class='tab'>Tab 3 Content</div>
<h2>History Tabs</h2>
<ul id='tabs2' class='ui-helper-clearfix''>
<li><a href='#tab4'>Tab 4</a></li>
<li><a href='#tab5'>Tab 5</a></li>
<li><a href='#tab6'>Tab 6</a></li>
</ul>
<div id='tab4' class='tab'>Tab 4 Content</div>
<div id='tab5' class='tab'>Tab 5 Content</div>
<div id='tab6' class='tab'>Tab 6 Content</div>
</div>
<script type='text/javascript'>DEMO_HTML = document.getElementById('demo-html').innerHTML</script>
<script type='text/javascript' src='../../steal/steal.js'></script>
<script type='text/javascript' id="demo-source">
steal('jquery/controller').then(function(){
$.Controller("Tabs",{
init : function(){
this.element.children("li:first").addClass('active')
var tab = this.tab;
this.element.children("li:gt(0)").each(function(){
tab($(this)).hide()
})
},
tab : function(li){
return $(li.find("a").attr("href"))
},
"li click" : function(el, ev){
ev.preventDefault();
this.activate(el)
},
activate : function(el){
this.tab(this.find('.active').removeClass('active')).hide()
this.tab(el.addClass('active')).show();
}
})
//inherit from tabs
Tabs("HistoryTabs",{
// ignore clicks
"li click" : function(){},
// listen for history changes
"{window} hashchange" : function(ev){
var hash = window.location.hash;
this.activate(hash === '' || hash === '#' ?
this.element.find("li:first") :
this.element.find("a[href="+hash+"]").parent()
)
}
})
//adds the controller to the element
$("#tabs1").tabs();
$("#tabs2").history_tabs();
})
</script>
</body>
</html>
\ No newline at end of file
This diff is collapsed.
steal("jquery/class") //load your app
.then('funcunit/qunit').then(function(){
module("jquery/class");
test("Creating", function(){
jQuery.Class.extend("Animal",
{
count: 0,
test: function() {
return this.match ? true : false
}
},
{
init: function() {
this.Class.count++;
this.eyes = false;
}
}
);
Animal.extend("Dog",
{
match : /abc/
},
{
init: function() {
this._super();
},
talk: function() {
return "Woof";
}
});
Dog.extend("Ajax",
{
count : 0
},
{
init: function( hairs ) {
this._super();
this.hairs = hairs;
this.setEyes();
},
setEyes: function() {
this.eyes = true;
}
});
new Dog();
new Animal();
new Animal();
var ajax = new Ajax(1000);
equals(2, Animal.count, "right number of animals");
equals(1, Dog.count, "right number of animals")
ok(Dog.match, "right number of animals")
ok(!Animal.match, "right number of animals")
ok(Dog.test(), "right number of animals")
ok(!Animal.test(), "right number of animals")
equals(1, Ajax.count, "right number of animals")
equals(2, Animal.count, "right number of animals");
equals(true, ajax.eyes, "right number of animals");
equals(1000, ajax.hairs, "right number of animals");
})
test("new instance",function(){
var d = Ajax.newInstance(6);
equals(6, d.hairs);
})
test("namespaces",function(){
var fb = $.Class.extend("Foo.Bar")
ok(Foo.Bar === fb, "returns class")
equals(fb.shortName, "Bar", "short name is right");
equals(fb.fullName, "Foo.Bar","fullName is right")
})
test("setups", function(){
var order = 0,
staticSetup,
staticSetupArgs,
staticInit,
staticInitArgs,
protoSetup,
protoInitArgs,
protoInit,
staticProps = {
setup: function() {
staticSetup = ++order;
staticSetupArgs = arguments;
return ["something"]
},
init: function() {
staticInit = ++order;
staticInitArgs = arguments;
}
},
protoProps = {
setup: function( name ) {
protoSetup = ++order;
return ["Ford: "+name];
},
init: function() {
protoInit = ++order;
protoInitArgs = arguments;
}
}
$.Class.extend("Car",staticProps,protoProps);
var geo = new Car("geo");
equals(staticSetup, 1);
equals(staticInit, 2);
equals(protoSetup, 3);
equals(protoInit, 4);
same($.makeArray(staticInitArgs), ["something"] )
same($.makeArray(protoInitArgs),["Ford: geo"] )
same($.makeArray(staticSetupArgs),[$.Class, "Car",staticProps, protoProps] ,"static construct");
//now see if staticSetup gets called again ...
Car.extend("Truck");
equals(staticSetup, 5, "Static setup is called if overwriting");
});
test("callback", function(){
var curVal = 0;
$.Class.extend("Car",{
show: function( value ) {
equals(curVal, value)
}
},{
show: function( value ) {
}
})
var cb = Car.callback('show');
curVal = 1;
cb(1)
curVal = 2;
var cb2 = Car.callback('show',2)
cb2();
});
test("callback error", 1,function(){
$.Class.extend("Car",{
show: function( value ) {
equals(curVal, value)
}
},{
show: function( value ) {
}
})
try{
Car.callback('huh');
ok(false, "I should have errored")
}catch(e){
ok(true, "Error was thrown")
}
})
test("Creating without extend", function(){
$.Class("Bar",{
ok : function(){
ok(true, "ok called")
}
});
new Bar().ok();
Bar("Foo",{
dude : function(){
ok(true, "dude called")
}
});
new Foo().dude(true);
})
/* Not sure I want to fix this yet.
test("Super in derived when parent doesn't have init", function(){
$.Class("Parent",{
});
Parent("Derived",{
init : function(){
this._super();
}
});
try {
new Derived();
ok(true, "Can call super in init safely")
} catch (e) {
ok(false, "Failed to call super in init with error: " + e)
}
})*/
});
\ No newline at end of file
<html>
<head>
<link rel="stylesheet" type="text/css" href="../../funcunit/qunit/qunit.css" />
</head>
<body>
<h1 id="qunit-header">Class Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
<script type='text/javascript' src='../../steal/steal.js?jquery/class/class_test.js'></script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Controller Example</title>
<style type='text/css'>
body {font-family: verdana}
.tabs {
padding: 0px; margin: 0px;
}
.tabs li {
float: left;
padding: 10px;
background-color: #F6F6F6;
list-style: none;
margin-left: 10px;
}
.tabs li a {
color: #1C94C4;
font-weight: bold;
text-decoration: none;
}
.tabs li.active a {
color: #F6A828;
cursor: default;
}
.tab {
border: solid 1px #F6A828;
}
/* clearfix from jQueryUI */
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
</style>
</head>
<body>
<div id="demo-html">
<ul id='tabs' class='ui-helper-clearfix''>
<li><a href='#tab1'>Tab 1</a></li>
<li><a href='#tab2'>Tab 2</a></li>
<li><a href='#tab3'>Tab 3</a></li>
</ul>
<div id='tab1' class='tab'>Tab 1 Content</div>
<div id='tab2' class='tab'>Tab 2 Content</div>
<div id='tab3' class='tab'>Tab 3 Content</div>
</div>
<script type='text/javascript' src='../../steal/steal.js'></script>
<script type='text/javascript'>
steal("jquery/controller", function(){
// create a new Tabs class
$.Controller("Tabs",{
// initialize widget
init : function(el){
// activate the first tab
$(el).children("li:first").addClass('active')
// hide the other tabs
var tab = this.tab;
this.element.children("li:gt(0)").each(function(){
tab($(this)).hide()
})
},
// helper function finds the tab for a given li
tab : function(li){
return $(li.find("a").attr("href"))
},
// hides old active tab, shows new one
"li click" : function(el, ev){
ev.preventDefault();
this.tab(this.find('.active').removeClass('active')).hide()
this.tab(el.addClass('active')).show();
}
})
// adds the controller to the element
$("#tabs").tabs();
})
</script>
</body>
</html>
\ No newline at end of file
steal("jquery/controller",'jquery/controller/subscribe') //load your app
.then('funcunit/qunit') //load qunit
.then(function(){
module("jquery/controller")
test("subscribe testing works", function(){
var ta = $("<div/>").appendTo( $("#qunit-test-area") )
ta.html("click here")
var clicks = 0, destroys = 0;
var subscribes = 0;
$.Controller.extend("MyTest",{
click: function() {
clicks++
},
"a.b subscribe" : function() {
subscribes++
},
destroy: function() {
this._super()
destroys++;
}
})
ta.my_test();
ta.trigger("click")
equals(clicks,1, "can listen to clicks")
OpenAjax.hub.publish("a.b",{})
equals(subscribes,1, "can subscribe")
var controllerInstance = ta.controller('my_test')
ok( controllerInstance.Class == MyTest, "can get controller" )
controllerInstance.destroy()
equals(destroys,1, "destroy called once")
ok(!ta.controller(), "controller is removed")
OpenAjax.hub.publish("a.b",{})
equals(subscribes,1, "subscription is torn down")
ta.trigger("click")
equals(clicks,1, "No longer listening")
ta.my_test();
ta.trigger("click")
OpenAjax.hub.publish("a.b",{})
equals(clicks,2, "can listen again to clicks")
equals(subscribes,2, "can listen again to subscription")
ta.remove();
ta.trigger("click")
OpenAjax.hub.publish("a.b",{})
equals(clicks,2, "Clicks stopped")
equals(subscribes,2, "Subscribes stopped")
})
test("bind to any special", function(){
jQuery.event.special.crazyEvent = {
}
var called = false;
jQuery.Controller.extend("WeirdBind",{
crazyEvent: function() {
called = true;
}
})
var a = $("<div id='crazy'></div>").appendTo($("#qunit-test-area"))
a.weird_bind();
a.trigger("crazyEvent")
ok(called, "heard the trigger");
$("#qunit-test-area").html("")
})
test("parameterized actions", function(){
var called = false;
jQuery.Controller.extend("WeirderBind",{
"{parameterized}" : function() {
called = true;
}
})
var a = $("<div id='crazy'></div>").appendTo($("#qunit-test-area"))
a.weirder_bind({parameterized: "sillyEvent"});
a.trigger("sillyEvent")
ok(called, "heard the trigger")
$("#qunit-test-area").html("")
})
test("windowresize", function(){
var called = false;
jQuery.Controller.extend("WindowBind",{
"{window} resize" : function() {
called = true;
}
})
$("#qunit-test-area").html("<div id='weird'>")
$("#weird").window_bind();
$(window).trigger('resize')
ok(called,"got window resize event");
$("#qunit-test-area").html("")
})
// this.delegate(this.cached.header.find('tr'), "th", "mousemove", "th_mousemove");
test("delegate", function(){
var called = false;
jQuery.Controller.extend("DelegateTest",{
click: function() {}
})
var els = $("<div><span><a href='#'>click me</a></span></div>").appendTo($("#qunit-test-area"))
var c = els.delegate_test();
c.controller().delegate(els.find("span"), "a", "click", function(){
called = true;
})
els.find("a").trigger('click')
ok(called, "delegate works")
$("#qunit-test-area").html("")
})
test("inherit", function(){
var called = false;
$.Controller.extend( "Parent", {
click: function(){
called = true;
}
})
Parent.extend( "Child", {
})
var els = $("<div><span><a href='#'>click me</a></span></div>").appendTo($("#qunit-test-area"))
els.child();
els.find("a").trigger('click')
ok(called, "inherited the click method")
$("#qunit-test-area").html("")
});
test("objects in action", function(){
$.Controller('Thing',{
"{item} someEvent" : function(thing, ev){
ok(true, "called");
equals(ev.type, "someEvent","correct event")
equals(this.constructor.fullName, "Thing", "This is a controller isntance")
equals(thing.name,"Justin","Raw, not jQuery wrapped thing")
}
});
var thing1 = {name: "Justin"};
var ta = $("<div/>").appendTo( $("#qunit-test-area") )
ta.thing({item : thing1});
$(thing1).trigger("someEvent");
$("#qunit-test-area").html("");
});
test("dot",function(){
$.Controller("Dot",{
"foo.bar" : function(){
ok(true,'called')
}
});
var ta = $("<div/>").appendTo( $("#qunit-test-area") );
ta.dot().trigger("foo.bar");
$("#qunit-test-area").html("");
})
// HTMLFormElement[0] breaks
test("the right element", 1, function(){
$.Controller('FormTester',{
init : function(){
equals(this.element[0].nodeName.toLowerCase(), "form" )
}
})
$("<form><input name='one'/></form>").appendTo( $("#qunit-test-area") )
.form_tester();
$("#qunit-test-area").html("")
})
test("pluginName", function() {
// Testing for controller pluginName fixes as reported in
// http://forum.javascriptmvc.com/#topic/32525000000253001
// http://forum.javascriptmvc.com/#topic/32525000000488001
expect(6);
$.Controller("PluginName", {
pluginName : "my_plugin"
}, {
method : function(arg) {
ok(true, "Method called");
},
update : function(options) {
this._super(options);
ok(true, "Update called");
},
destroy : function() {
ok(true, "Destroyed");
this._super();
}
});
var ta = $("<div/>").addClass('existing_class').appendTo( $("#qunit-test-area") );
ta.my_plugin(); // Init
ok(ta.hasClass("my_plugin"), "Should have class my_plugin");
ta.my_plugin(); // Update
ta.my_plugin("method"); // method()
ta.controller().destroy(); // destroy
ok(!ta.hasClass("my_plugin"), "Shouldn't have class my_plugin after being destroyed");
ok(ta.hasClass("existing_class"), "Existing class should still be there");
})
test("inherit defaults", function() {
$.Controller.extend("BaseController", {
defaults : {
foo: 'bar'
}
}, {});
BaseController.extend("InheritingController", {
defaults : {
newProp : 'newVal'
}
}, {});
ok(InheritingController.defaults.foo === 'bar', 'Class must inherit defaults from the parent class');
ok(InheritingController.defaults.newProp == 'newVal', 'Class must have own defaults');
var inst = new InheritingController($('<div/>'), {});
ok(inst.options.foo === 'bar', 'Instance must inherit defaults from the parent class');
ok(inst.options.newProp == 'newVal', 'Instance must have defaults of it`s class');
});
test("update rebinding", 2, function(){
var first = true;
$.Controller("Rebinder", {
"{item} foo" : function(item, ev){
if(first){
equals(item.id, 1, "first item");
first = false;
} else {
equals(item.id, 2, "first item");
}
}
});
var item1 = {id: 1},
item2 = {id: 2},
el = $('<div>').rebinder({item: item1})
$(item1).trigger("foo")
el.rebinder({item: item2});
$(item2).trigger("foo")
})
});
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Controller Example</title>
<style type='text/css'>
</style>
</head>
<body>
<div id="demo-html">
<form action='' id='createRecipes'>
<input type='text' name='name'/>
<input type='submit' value='Create Recipe'/>
</form>
</div>
<script type='text/javascript' src='../../steal/steal.js'></script>
<script type='text/javascript'>
steal("jquery/controller",
"jquery/model",
"jquery/dom/form_params",
"jquery/dom/fixture",
function(){
$.fixture.delay = 2000;
$.fixture("POST /recipes",function(){
return {};
})
$.Model('Recipe',{
create : "/recipes"
},{});
$.Controller('Creator',{
"{recipe} created" : function(){
this.update({recipe : new Recipe()});
this.element[0].reset();
this.find("[type=submit]").val("Create Recipe")
},
"submit" : function(el, ev){
ev.preventDefault();
var recipe = this.options.recipe;
recipe.attrs( this.element.formParams() );
this.find("[type=submit]").val("Saving...")
recipe.save();
}
});
$('#createRecipes').creator({recipe : new Recipe()})
})
</script>
</body>
</html>
\ No newline at end of file
@page jquery.controller.listening Listening To Events
@parent jQuery.Controller
Controllers make creating and tearing down event handlers extremely
easy. The tearingdown of event handlers is especially important
in preventing memory leaks in long lived applications.
## Automatic Binding
When a [jQuery.Controller.prototype.setup new controller is created],
contoller checks its prototype methods for functions that are named like
event handlers. It binds these functions to the
controller's [jQuery.Controller.prototype.element element] with
event delegation. When
the controller is destroyed (or it's element is removed from the page), controller
will unbind its event handlers automatically.
For example, each of the following controller's functions will automatically
bound:
$.Controller("Crazy",{
// listens to all clicks on this element
"click" : function(el, ev){},
// listens to all mouseovers on
// li elements withing this controller
"li mouseover" : function(el, ev){}
// listens to the window being resized
"{window} resize" : function(window, ev){}
})
Controller will bind function names with spaces, standard DOM events, and
event names in $.event.special.
In general, Controller will know automatically when to bind event handler functions except for
one case - event names without selectors that are not in $.event.special.
But to correct for this, you just need to add the
function to the [jQuery.Controller.static.listensTo listensTo]
property. Here's how:
$.Controller("MyShow",{
listensTo: ["show"]
},{
show: function( el, ev ) {
el.show();
}
})
$('.show').my_show().trigger("show");
## Callback parameters
Event handlers bound with controller are called back with the element and the event
as parameters. <b>this</b> refers to the controller instance. For example:
$.Controller("Tabs",{
// li - the list element that was clicked
// ev - the click event
"li click" : function(li, ev){
this.tab(li).hide()
},
tab : function(li){
return $(li.find("a").attr("href"))
}
})
## Templated Event Bindings
One of Controller's most powerful features is templated event
handlers. You can parameterize the event name,
the selector, or event the root element.
### Templating event names and selectors:
Often, you want to make a widget's behavior
configurable. A common example is configuring which event
a menu should show a sub-menu (ex: on click or mouseenter). The
following controller lets you configure when a menu should show
sub-menus:
The following makes two buttons. One says hello on click,
the other on a 'tap' event.
$.Controller("Menu",{
"li {showEvent}" : function(el){
el.children('ul').show()
}
})
$("#clickMe").menu({showEvent : "click"});
$("#touchMe").menu({showEvent : "mouseenter"});
$.Controller replaces value in <code>{}</code> with
values in a
controller's [jQuery.Controller.prototype.options options]. This means
we can easily provide a default <code>showEvent</code> value and create
a menu without providing a value like:
$.Controller("Menu",
{
defaults : {
showEvent : "click"
}
},
{
"li {showEvent}" : function(el){
el.children('ul').show()
}
});
$("#clickMe").menu(); //defaults to using click
Sometimes, we might might want to configure our widget to
use different elements. The following makes the menu widget's
<code>button</code> elements configurable:
$.Controller("Menu",{
"{button} {showEvent}" : function(el){
el.children('ul').show()
}
})
$('#buttonMenu').menu({button: "button"});
### Templating the root element.
Finally, controller lets you bind to objects outside
of the [jQuery.Controller.prototype.element controller's element].
The following listens to clicks on the window:
$.Controller("HideOnClick",{
"{window} click" : function(){
this.element.hide()
}
})
The following listens to Todos being created:
$.Controller("NewTodos",{
"{App.Models.Todo} created" : function(Todo, ev, newTodo){
this.element.append("newTodos.ejs", newTodo)
}
});
But instead of making NewTodos only work with the Todo model,
we can make it configurable:
$.Controller("Newbie",{
"{model} created" : function(Model, ev, newItem){
this.element.append(this.options.view, newItem)
}
});
$('#newItems').newbie({
model: App.Models.Todo,
view: "newTodos.ejs"
})
### How Templated events work
When looking up a value to replace <code>{}</code>,
controller first looks up the item in the options, then it looks
up the value in the window object. It does not use eval to look up the
object. Instead it uses [jQuery.String.getObject].
## Subscribing to OpenAjax messages and custom bindings
The jquery/controller/subscribe plugin allows controllers to listen
to OpenAjax.hub messages like:
$.Controller("Listener",{
"something.updated subscribe" : function(called, data){
}
})
You can create your own binders by adding to [jQuery.Controller.static.processors].
## Manually binding to events.
The [jQuery.Controller.prototype.bind] and [jQuery.Controller.prototype.delegate]
methods let you listen to events on other elements. These event handlers will
be unbound when the controller instance is destroyed.
@page jquery.controller.plugin The generated jQuery plugin
@parent jQuery.Controller
When you create a controller, it creates a jQuery plugin that can be
used to:
- Create controllers on an element or elements
- Call controller methods
- Update a controller
For example, the following controller:
$.Controller("My.Widget",{
say : function(){
alert(this.options.message);
}
})
creates a <code>jQuery.fn.my_widget</code> method that you can use like:
// create my_widget on each .thing
$(".thing").my_widget({message : "Hello"})
// alerts "Hello"
$(".thing").my_widget("say");
// updates the message option
$(".thing").my_widget({message : "World"});
// alerts "World"
$(".thing").my_widget("say");
Note that in every case, the my_widget plugin
returns the original jQuery collection for chaining (<code>$('.thing')</code>). If you want to
get a value from a controller, use the [jQuery.fn.controllers] or [jQuery.fn.controller].
## Creating controllers
When a controller's jQuery plugin helper is used on a jQuery collection, it goes to each
element and tests if it has a controller instance on the element. If it does not, it creates one.
It calls <code>new YourController</code> with the element and any additional arguments you passed
to the jQuery plugin helper. So for example, say there are 2 elements in <code>$('.thing')</code>.
This:
$(".thing").my_widget({message : "Hello"})
Does the exact same thing as:
var things = $('.thing'),
options = {message : "Hello"};
new My.Widget(things[0],options);
new My.Widget(things[1],options);
Note, when a <code>new Class</code> is created, it calls your
class's prototype setup and init methods. Read [jQuery.Controller.prototype.setup controller's setup]
for the details on what happens when a new controller is created.
## Calling methods on controllers
Once a Controller is already on an element, you can call methods on it with the same jQuery
helper. The first param to the helper is the name of the method, the following params are
passed to the jQuery function. For example:
$.Controller("Adder",{
sum : function(first, second, third){
this.element.text(first+second+third);
}
})
// add an adder to the page
$("#myadder").adder()
// show the sum of 1+2+3
$("#myadder").adder("sum",1,2,3);
## Naming
By default, a controller's jQuery helper is the controller name:
- [jQuery.String.underscore underscored]
- "." replaced with "_"
- with Controllers removed.
Here are some examples:
$.Controller("Foo") // -> .foo()
$.Controller("Foo.Bar") // -> .foo_bar()
$.Controller("Foo.Controllers.Bar") // -> .foo_bar()
You can overwrite the Controller's default name by setting a static pluginName property:
$.Controller("My.Tabs",
{
pluginName: "tabs"
},
{ ... })
$("#tabs").tabs()
<html>
<head>
<link rel="stylesheet" type="text/css" href="../../funcunit/qunit/qunit.css" />
<style>
body {
margin: 0px; padding: 0px;
}
</style>
<script type='text/javascript' src='../../steal/steal.js?jquery/controller/controller_test.js'></script>
</head>
<body>
<h1 id="qunit-header">Controller Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<div id="test-content"></div>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="../../../funcunit/qunit/qunit.css" />
<title>route QUnit Test</title>
<script type='text/javascript' src='../../../steal/steal.js?jquery/controller/route/route_test.js'></script>
</head>
<body>
<h1 id="qunit-header">route Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<div id="test-content"></div>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>route</title>
<style type='text/css'>
body {font-family: verdana}
.error {border: solid 1px red;}
.error_text { color: red; font-size: 10px;}
td {padding: 3px;}
</style>
</head>
<body>
<h1>route Demo</h1>
<a href="#!foo/bar">foo/bar</a>
<a href="#!foo/car">foo/car</a>
<a href="#!">empty</a>
<script type='text/javascript'
src='../../../steal/steal.js'>
</script>
<script type='text/javascript'>
steal('jquery/controller/route', function(){
$.Controller("Router",{
"foo/:bar route" : function(){
console.log("foo/:bar")
},
"route" : function(){
console.log("route")
}
})
new Router(window)
})
</script>
</body>
</html>
\ No newline at end of file
steal('jquery/dom/route','jquery/controller', function(){
/**
*
* ":type route" //
*
* @param {Object} el
* @param {Object} event
* @param {Object} selector
* @param {Object} cb
*/
jQuery.Controller.processors.route = function(el, event, selector, funcName, controller){
$.route(selector||"")
var batchNum;
var check = function(ev, attr, how){
if($.route.attr('route') === (selector||"") &&
(ev.batchNum === undefined || ev.batchNum !== batchNum ) ){
batchNum = ev.batchNum;
var d = $.route.attrs();
delete d.route;
controller[funcName](d)
}
}
$.route.bind('change',check);
return function(){
$.route.unbind('change',check)
}
}
})
steal('funcunit/qunit','./route',function(){
module("route");
test("route testing works", function(){
ok(true,"an assert is run");
});
});
\ No newline at end of file
<html>
<head>
<link rel="stylesheet" type="text/css" href="../../../steal/test/qunit/qunit.css" />
<style>
body {
margin: 0px; padding: 0px;
}
</style>
<script type='text/javascript' src='../../../steal/steal.js?steal[app]=jquery/controller/subscribe/test/funcunit'></script>
</head>
<body>
<h1 id="qunit-header">subscribe Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<div id="test-content"></div>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>hover</title>
<style type='text/css'>
body {font-family: verdana}
.error {border: solid 1px red;}
.error_text { color: red; font-size: 10px;}
td {padding: 3px;}
.subscribe, .subscribes {
border: solid 1px green;
}
.subscribed {
background-color: yellow;
}
.mysubscribe {
border: solid 1px red;
}
</style>
</head>
<body>
<div id="testSubscribe">
<div id="subscribe1">
subscribe me
</div>
<h2><a href="#" id="off">Turn OFF Above</a></h2>
</div>
<script type='text/javascript'
src='../../../steal/steal.js'>
</script>
<script type='text/javascript'>
steal('jquery/controller/subscribe').then(function(){
$.Controller('subscribeTest',{
onDocument: false
},
{
"#subscribe1 click": function(el, ev){
ev.stopPropagation();
this.publish("oaSubscribe1", {"params":"Hola Mundo"});
},
"oaSubscribe1 subscribe": function(called, data){
alert("subscribe1 " + data.params + " : " + this.Class.shortName);
}
});
var subscribeController = new subscribeTest($("#testSubscribe")[0]);
$("#off").bind("click",function(){
subscribeController.destroy();
})
});
</script>
</body>
</html>
/*global OpenAjax: true */
steal('jquery/controller', 'jquery/lang/openajax').then(function() {
/**
* @function jQuery.Controller.static.processors.subscribe
* @parent jQuery.Controller.static.processors
* @plugin jquery/controller/subscribe
* Adds OpenAjax.Hub subscribing to controllers.
*
* $.Controller("Subscriber",{
* "recipe.updated subscribe" : function(called, recipe){
*
* },
* "todo.* subscribe" : function(called, todo){
*
* }
* })
*
* You should typically be listening to jQuery triggered events when communicating between
* controllers. Subscribe should be used for listening to model changes.
*
* ### API
*
* This is the call signiture for the processor, not the controller subscription callbacks.
*
* @param {HTMLElement} el the element being bound. This isn't used.
* @param {String} event the event type (subscribe).
* @param {String} selector the subscription name
* @param {String} cb the callback function's name
*/
jQuery.Controller.processors.subscribe = function( el, event, selector, cb, controller ) {
var subscription = OpenAjax.hub.subscribe(selector, function(){
return controller[cb].apply(controller, arguments)
});
return function() {
OpenAjax.hub.unsubscribe(subscription);
};
};
/**
* @add jQuery.Controller.prototype
*/
//breaker
/**
* @function publish
* @hide
* Publishes a message to OpenAjax.hub.
* @param {String} message Message name, ex: "Something.Happened".
* @param {Object} data The data sent.
*/
jQuery.Controller.prototype.publish = function() {
OpenAjax.hub.publish.apply(OpenAjax.hub, arguments);
};
});
\ No newline at end of file
<html>
<head>
<link rel="stylesheet" type="text/css" href="../../../funcunit/qunit/qunit.css" />
<style>
body {
margin: 0px; padding: 0px;
}
</style>
<script type='text/javascript' src='../../../steal/steal.js?jquery/controller/view/test/qunit/controller_view_test.js'></script>
</head>
<body>
<h1 id="qunit-header">Controller Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<div id="test-content"></div>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
</body>
</html>
\ No newline at end of file
steal('jquery/controller/view','jquery/view/micro','funcunit/qunit') //load qunit
.then(function(){
module("jquery/controller/view");
test("this.view", function(){
$.Controller.extend("jquery.Controller.View.Test.Qunit",{
init: function() {
this.element.html(this.view())
}
})
jQuery.View.ext = ".micro";
$("#qunit-test-area").append("<div id='cont_view'/>");
new jquery.Controller.View.Test.Qunit( $('#cont_view') );
ok(/Hello World/i.test($('#cont_view').text()),"view rendered")
});
test("test.suffix.doubling", function(){
$.Controller.extend("jquery.Controller.View.Test.Qunit",{
init: function() {
this.element.html(this.view('init.micro'))
}
})
jQuery.View.ext = ".ejs"; // Reset view extension to default
equal(".ejs", jQuery.View.ext);
$("#qunit-test-area").append("<div id='suffix_test_cont_view'/>");
new jquery.Controller.View.Test.Qunit( $('#suffix_test_cont_view') );
ok(/Hello World/i.test($('#suffix_test_cont_view').text()),"view rendered")
});
test("complex paths nested inside a controller directory", function(){
$.Controller.extend("Myproject.Controllers.Foo.Bar");
var path = jQuery.Controller._calculatePosition(Myproject.Controllers.Foo.Bar, "init.ejs", "init")
equals(path, "//myproject/views/foo/bar/init.ejs", "view path is correct")
$.Controller.extend("Myproject.Controllers.FooBar");
path = jQuery.Controller._calculatePosition(Myproject.Controllers.FooBar, "init.ejs", "init")
equals(path, "//myproject/views/foo_bar/init.ejs", "view path is correct")
})
});
//we probably have to have this only describing where the tests are
steal('jquery/controller/view','jquery/view/micro') //load your app
.then('funcunit/qunit') //load qunit
.then("./controller_view_test.js")
steal('jquery/controller', 'jquery/view').then(function( $ ) {
var URI = steal.URI || steal.File;
jQuery.Controller.getFolder = function() {
return jQuery.String.underscore(this.fullName.replace(/\./g, "/")).replace("/Controllers", "");
};
jQuery.Controller._calculatePosition = function( Class, view, action_name ) {
var classParts = Class.fullName.split('.'),
classPartsWithoutPrefix = classParts.slice(0);
classPartsWithoutPrefix.splice(0, 2); // Remove prefix (usually 2 elements)
var classPartsWithoutPrefixSlashes = classPartsWithoutPrefix.join('/'),
hasControllers = (classParts.length > 2) && classParts[1] == 'Controllers',
path = hasControllers? jQuery.String.underscore(classParts[0]): jQuery.String.underscore(classParts.join("/")),
controller_name = jQuery.String.underscore(classPartsWithoutPrefix.join('/')).toLowerCase(),
suffix = (typeof view == "string" && /\.[\w\d]+$/.test(view)) ? "" : jQuery.View.ext;
//calculate view
if ( typeof view == "string" ) {
if ( view.substr(0, 2) == "//" ) { //leave where it is
} else {
view = "//" + URI(path).join( 'views/' + (view.indexOf('/') !== -1 ? view : (hasControllers ? controller_name + '/' : "") + view)) + suffix;
}
} else if (!view ) {
view = "//" + URI(path).join('views/' + (hasControllers ? controller_name + '/' : "") + action_name.replace(/\.|#/g, '').replace(/ /g, '_'))+ suffix;
}
return view;
};
var calculateHelpers = function( myhelpers ) {
var helpers = {};
if ( myhelpers ) {
if ( jQuery.isArray(myhelpers) ) {
for ( var h = 0; h < myhelpers.length; h++ ) {
jQuery.extend(helpers, myhelpers[h]);
}
}
else {
jQuery.extend(helpers, myhelpers);
}
} else {
if ( this._default_helpers ) {
helpers = this._default_helpers;
}
//load from name
var current = window;
var parts = this.constructor.fullName.split(/\./);
for ( var i = 0; i < parts.length; i++ ) {
if(current){
if ( typeof current.Helpers == 'object' ) {
jQuery.extend(helpers, current.Helpers);
}
current = current[parts[i]];
}
}
if (current && typeof current.Helpers == 'object' ) {
jQuery.extend(helpers, current.Helpers);
}
this._default_helpers = helpers;
}
return helpers;
};
/**
* @add jQuery.Controller.prototype
*/
jQuery.Controller.prototype.
/**
* @tag view
* Renders a View template with the controller instance. If the first argument
* is not supplied,
* it looks for a view in /views/controller_name/action_name.ejs.
* If data is not provided, it uses the controller instance as data.
* @codestart
* TasksController = $.Controller.extend('TasksController',{
* click: function( el ) {
* // renders with views/tasks/click.ejs
* el.html( this.view() )
* // renders with views/tasks/under.ejs
* el.after( this.view("under", [1,2]) );
* // renders with views/tasks/under.micro
* el.after( this.view("under.micro", [1,2]) );
* // renders with views/shared/top.ejs
* el.before( this.view("shared/top", {phrase: "hi"}) );
* }
* })
* @codeend
* @plugin jquery/controller/view
* @return {String} the rendered result of the view.
* @param {String} [view] The view you are going to render. If a view isn't explicity given
* this function will try to guess at the correct view as show in the example code above.
* @param {Object} [data] data to be provided to the view. If not present, the controller instance
* is used.
* @param {Object} [myhelpers] an object of helpers that will be available in the view. If not present
* this controller class's "Helpers" property will be used.
*
*/
view = function( view, data, myhelpers ) {
//shift args if no view is provided
if ( typeof view != "string" && !myhelpers ) {
myhelpers = data;
data = view;
view = null;
}
//guess from controller name
view = jQuery.Controller._calculatePosition(this.Class, view, this.called);
//calculate data
data = data || this;
//calculate helpers
var helpers = calculateHelpers.call(this, myhelpers);
return jQuery.View(view, data, helpers); //what about controllers in other folders?
};
});
\ No newline at end of file
/**
* @add jQuery.fn
*/
steal('jquery/dom').then(function(){
/**
* @function closest
* @parent dom
* @plugin jquery/dom/closest
* Overwrites closest to allow open > selectors. This allows controller
* actions such as:
*
* ">li click" : function( el, ev ) { ... }
*/
var oldClosest = jQuery.fn.closest;
jQuery.fn.closest = function(selectors, context){
var rooted = {}, res, result, thing, i, j, selector, rootedIsEmpty = true, selector, selectorsArr = selectors;
if(typeof selectors == "string") selectorsArr = [selectors];
$.each(selectorsArr, function(i, selector){
if(selector.indexOf(">") == 0 ){
if(selector.indexOf(" ") != -1){
throw " closest does not work with > followed by spaces!"
}
rooted[( selectorsArr[i] = selector.substr(1) )] = selector;
if(typeof selectors == "string") selectors = selector.substr(1);
rootedIsEmpty = false;
}
})
res = oldClosest.call(this, selectors, context);
if(rootedIsEmpty) return res;
i =0;
while(i < res.length){
result = res[i], selector = result.selector;
if (rooted[selector] !== undefined) {
result.selector = rooted[selector];
rooted[selector] = false;
if(typeof result.selector !== "string" || result.elem.parentNode !== context ){
res.splice(i,1);
continue;
}
}
i++;
}
return res;
}
})
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Compare Element Positions</title>
<style type='text/css'>
body {font-family: verdana}
div {
border: solid 1px black;
margin: 5px;
padding: 5px;
font-size: 12px;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.hide {
display: none;
}
h3 {
margin: 20px 0px 0px 0px;
}
th {
padding: 0px 5px;
color: gray;
}
td {
padding: 0px 5px;
}
</style>
</head>
<body>
<p>Click 2 elements to compare them.</p>
<pre>
<code>$('.red').compare($('.green')) = <span id='result'></span></code>
</pre>
<div id="demo-html">
<div>
A
<div>A.1</div>
<div>A.2</div>
</div>
<div>
B
</div>
</div>
<h3 class='hide'>Key</h3>
<table class='hide'>
<tr><th>Bits</th><th>Number</th><th>Meaning</th></tr>
<tr><td>000000</td><td>0</td><td>Elements are identical.</td></tr>
<tr><td>000001</td><td>1</td><td>The nodes are in different documents (or one is outside of a document).</td></tr>
<tr><td>000010</td><td>2</td><td>Node B precedes Node A.</td></tr>
<tr><td>000100</td><td>4</td><td>Node A precedes Node B.</td></tr>
<tr><td>001000</td><td>8</td><td>Node B contains Node A.</td></tr>
<tr><td>010000</td><td>16</td><td>Node A contains Node B.</td></tr>
</table>
<script type='text/javascript'
src='../../../steal/steal.js'>
</script>
<script id="demo-source" type='text/javascript'>
steal('jquery/dom/compare').then(function(){
var placing = 'red'
//on click, set red and green and compare positions
$('div').click(function(ev){
var next = placing == 'red' ? 'green' : 'red';
$('.'+placing).removeClass(placing)
$(this).addClass(placing)
placing = next
ev.stopPropagation();
//don't worry about repeat queries for simple example
if($('.green').length){
$("#result").text( $('.red').compare($('.green')) )
}
})
$(function(){
if(window.parent == window){
$('.hide').show()
}
})
})
</script>
</body>
</html>
\ No newline at end of file
/**
* @add jQuery.fn
*/
steal('jquery/dom').then(function($){
/**
* @function compare
* @parent dom
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/dom/compare/compare.js
*
* Compares the position of two nodes and returns a bitmask detailing how they are positioned
* relative to each other.
*
* $('#foo').compare($('#bar')) //-> Number
*
* You can expect it to return the same results as
* [http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition | compareDocumentPosition].
* Parts of this documentation and source come from [http://ejohn.org/blog/comparing-document-position | John Resig].
*
* ## Demo
* @demo jquery/dom/compare/compare.html
* @test jquery/dom/compare/qunit.html
* @plugin dom/compare
*
*
* @param {HTMLElement|jQuery} element an element or jQuery collection to compare against.
* @return {Number} A bitmap number representing how the elements are positioned from each other.
*
* If the code looks like:
*
* $('#foo').compare($('#bar')) //-> Number
*
* Number is a bitmap with with the following values:
* <table class='options'>
* <tr><th>Bits</th><th>Number</th><th>Meaning</th></tr>
* <tr><td>000000</td><td>0</td><td>Elements are identical.</td></tr>
* <tr><td>000001</td><td>1</td><td>The nodes are in different
* documents (or one is outside of a document).</td></tr>
* <tr><td>000010</td><td>2</td><td>#bar precedes #foo.</td></tr>
* <tr><td>000100</td><td>4</td><td>#foo precedes #bar.</td></tr>
* <tr><td>001000</td><td>8</td><td>#bar contains #foo.</td></tr>
* <tr><td>010000</td><td>16</td><td>#foo contains #bar.</td></tr>
* </table>
*/
jQuery.fn.compare = function(element){ //usually
//element is usually a relatedTarget, but element/c it is we have to avoid a few FF errors
try{ //FF3 freaks out with XUL
element = element.jquery ? element[0] : element;
}catch(e){
return null;
}
if (window.HTMLElement) { //make sure we aren't coming from XUL element
var s = HTMLElement.prototype.toString.call(element)
if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]' || s === '[object Window]') {
return null;
}
}
if(this[0].compareDocumentPosition){
return this[0].compareDocumentPosition(element);
}
if(this[0] == document && element != document) return 8;
var number = (this[0] !== element && this[0].contains(element) && 16) + (this[0] != element && element.contains(this[0]) && 8),
docEl = document.documentElement;
if(this[0].sourceIndex){
number += (this[0].sourceIndex < element.sourceIndex && 4)
number += (this[0].sourceIndex > element.sourceIndex && 2)
number += (this[0].ownerDocument !== element.ownerDocument ||
(this[0] != docEl && this[0].sourceIndex <= 0 ) ||
(element != docEl && element.sourceIndex <= 0 )) && 1
}else{
var range = document.createRange(),
sourceRange = document.createRange(),
compare;
range.selectNode(this[0]);
sourceRange.selectNode(element);
compare = range.compareBoundaryPoints(Range.START_TO_START, sourceRange);
}
return number;
}
});
\ No newline at end of file
steal("jquery/dom/compare") //load your app
.then('funcunit/qunit').then(function(){
module("jquery/dom/compare")
test("Compare cases", function(){
$(document.body).append("<div id='outer'><div class='first'></div><div class='second'></div>")
var outer = $("#outer"),
first= outer.find(".first"), second = outer.find('.second')
equals(outer.compare(outer) , 0, "identical elements")
var outside = document.createElement("div")
ok(outer.compare(outside) & 1, "different documents")
equals(outer.compare(first), 20, "A container element");
equals(outer.compare(second), 20, "A container element");
equals(first.compare(outer), 10, "A parent element");
equals(second.compare(outer), 10, "A parent element");
equals(first.compare(second), 4, "A sibling elements");
equals(second.compare(first), 2, "A sibling elements");
outer.remove()
});
});
\ No newline at end of file
<html>
<head>
<link rel="stylesheet" type="text/css" href="../../../funcunit/qunit/qunit.css" />
<style>
body {
margin: 0px; padding: 0px;
}
</style>
</head>
<body>
<h1 id="qunit-header">jQuery Dom Compare Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<script type='text/javascript' src='../../../steal/steal.js?jquery/dom/compare/compare_test.js'></script>
</body>
</html>
\ No newline at end of file
steal('jquery/lang/json',function() {
// break
/**
* @function jQuery.cookie
* @parent dom
* @plugin jquery/dom/cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*
* JavaScriptMVC's packaged cookie plugin is written by
* Klaus Hartl (stilbuero.de)<br />
* Dual licensed under the MIT and GPL licenses:<br />
* http://www.opensource.org/licenses/mit-license.php<br />
* http://www.gnu.org/licenses/gpl.html
* </p>
* <p>
* Create a cookie with the given name and value and other optional parameters.
* / Get the value of a cookie with the given name.
* </p>
* <h3>Quick Examples</h3>
*
* Set the value of a cookie.
*
* $.cookie('the_cookie', 'the_value');
*
* Create a cookie with all available options.
* @codestart
* $.cookie('the_cookie', 'the_value',
* { expires: 7, path: '/', domain: 'jquery.com', secure: true });
* @codeend
*
* Create a session cookie.
* @codestart
* $.cookie('the_cookie', 'the_value');
* @codeend
*
* Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
* used when the cookie was set.
* @codestart
* $.cookie('the_cookie', null);
* @codeend
*
* Get the value of a cookie.
* @codestart
* $.cookie('the_cookie');
* @codeend
*
*
* @param {String} [name] The name of the cookie.
* @param {String} [value] The value of the cookie.
* @param {Object} [options] An object literal containing key/value pairs to provide optional cookie attributes.<br />
* @param {Number|Date} [expires] Either an integer specifying the expiration date from now on in days or a Date object.
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
* If set to null or omitted, the cookie will be a session cookie and will not be retained
* when the the browser exits.<br />
* @param {String} [path] The value of the path atribute of the cookie (default: path of page that created the cookie).<br />
* @param {String} [domain] The value of the domain attribute of the cookie (default: domain of page that created the cookie).<br />
* @param {Boolean} secure If true, the secure attribute of the cookie will be set and the cookie transmission will
* require a secure protocol (like HTTPS).<br />
* @return {String} the value of the cookie or {undefined} when setting the cookie.
*/
jQuery.cookie = function(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options ||
{};
if (value === null) {
value = '';
options.expires = -1;
}
if (typeof value == 'object' && jQuery.toJSON) {
value = jQuery.toJSON(value);
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
}
else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
// CAUTION: Needed to parenthesize options.path and options.domain
// in the following expressions, otherwise they evaluate to undefined
// in the packed version for some reason...
var path = options.path ? '; path=' + (options.path) : '';
var domain = options.domain ? '; domain=' + (options.domain) : '';
var secure = options.secure ? '; secure' : '';
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
}
else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
if (jQuery.evalJSON && cookieValue && cookieValue.match(/^\s*\{/)) {
try {
cookieValue = jQuery.evalJSON(cookieValue);
}
catch (e) {
}
}
return cookieValue;
}
};
});
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>CurStyles Performance Test/Demo</title>
<style type='text/css'>
body {font-family: verdana}
#content {height: 100px; width: 300px;
margin: 20px;
padding: 10px;
border: solid 1px black;
cursor: pointer;
}
</style>
</head>
<body>
<h1>CurStyles Performance</h1>
<p>This demo shows how $.curStyles out-performs $.curCSS</p>
<div id="demo-html">
<div id='content'>
Click To Run
</div>
</div>
<script type='text/javascript'
src='../../../steal/steal.js'></script>
<script type='text/javascript' id="demo-source">
steal('jquery/dom/cur_styles').then(function(){
$.fn.fastHeight = function(){
var sum = this[0] && this[0].offsetHeight;
$.each(this.curStyles(
"borderTopWidth",
"borderBottomWidth",
"paddingTop",
"paddingBottom"), function(name, val){
sum -= parseInt(val) || 0;
});
return sum;
}
var test = function(func){
var start = new Date(),
content = $("#content");
for(var i =0; i < 2000; i++){
content[func]()
}
return ( new Date() - start );
};
$("#content").click(function(){
var height = test("height"),
fastheight = test("fastHeight");
$("#content").html("jQuery's height: <b>"+
height+
"</b>ms<br/>fastHeight: <b>"+
fastheight+
"</b>ms"
)
});
});
</script>
</body>
</html>
\ No newline at end of file
steal('jquery/dom').then(function( $ ) {
var getComputedStyle = document.defaultView && document.defaultView.getComputedStyle,
rupper = /([A-Z])/g,
rdashAlpha = /-([a-z])/ig,
fcamelCase = function( all, letter ) {
return letter.toUpperCase();
},
getStyle = function( elem ) {
if ( getComputedStyle ) {
return getComputedStyle(elem, null);
}
else if ( elem.currentStyle ) {
return elem.currentStyle;
}
},
rfloat = /float/i,
rnumpx = /^-?\d+(?:px)?$/i,
rnum = /^-?\d/;
/**
* @add jQuery
*/
//
/**
* @function curStyles
* @param {HTMLElement} el
* @param {Array} styles An array of style names like <code>['marginTop','borderLeft']</code>
* @return {Object} an object of style:value pairs. Style names are camelCase.
*/
$.curStyles = function( el, styles ) {
if (!el ) {
return null;
}
var currentS = getStyle(el),
oldName, val, style = el.style,
results = {},
i = 0,
left, rsLeft, camelCase, name;
for (; i < styles.length; i++ ) {
name = styles[i];
oldName = name.replace(rdashAlpha, fcamelCase);
if ( rfloat.test(name) ) {
name = jQuery.support.cssFloat ? "float" : "styleFloat";
oldName = "cssFloat";
}
if ( getComputedStyle ) {
name = name.replace(rupper, "-$1").toLowerCase();
val = currentS.getPropertyValue(name);
if ( name === "opacity" && val === "" ) {
val = "1";
}
results[oldName] = val;
} else {
camelCase = name.replace(rdashAlpha, fcamelCase);
results[oldName] = currentS[name] || currentS[camelCase];
if (!rnumpx.test(results[oldName]) && rnum.test(results[oldName]) ) { //convert to px
// Remember the original values
left = style.left;
rsLeft = el.runtimeStyle.left;
// Put in the new values to get a computed value out
el.runtimeStyle.left = el.currentStyle.left;
style.left = camelCase === "fontSize" ? "1em" : (results[oldName] || 0);
results[oldName] = style.pixelLeft + "px";
// Revert the changed values
style.left = left;
el.runtimeStyle.left = rsLeft;
}
}
}
return results;
};
/**
* @add jQuery.fn
*/
$.fn
/**
* @parent dom
* @plugin jquery/dom/cur_styles
* @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquery/dom/cur_styles/cur_styles.js
* @test jquery/dom/cur_styles/qunit.html
* Use curStyles to rapidly get a bunch of computed styles from an element.
* <h3>Quick Example</h3>
* @codestart
* $("#foo").curStyles('float','display') //->
* // {
* // cssFloat: "left", display: "block"
* // }
* @codeend
* <h2>Use</h2>
* <p>An element's <b>computed</b> style is the current calculated style of the property.
* This is different than the values on <code>element.style</code> as
* <code>element.style</code> doesn't reflect styles provided by css or the browser's default
* css properties.</p>
* <p>Getting computed values individually is expensive! This plugin lets you get all
* the style properties you need all at once.</p>
* <h2>Demo</h2>
* <p>The following demo illustrates the performance improvement curStyle provides by providing
* a faster 'height' jQuery function called 'fastHeight'.</p>
* @demo jquery/dom/cur_styles/cur_styles.html
* @param {String} style pass style names as arguments
* @return {Object} an object of style:value pairs
*/
.curStyles = function() {
return $.curStyles(this[0], $.makeArray(arguments));
};
});
\ No newline at end of file
steal("jquery/dom/dimensions",'jquery/view/micro') //load your app
.then('funcunit/qunit').then(function(){
module("jquery/dom/curStyles");
test("reading", function(){
$("#qunit-test-area").html("//jquery/dom/cur_styles/test/curStyles.micro",{})
var res = $.curStyles( $("#styled")[0],
["padding-left",
'position',
'display',
"margin-top",
"borderTopWidth",
"float"] );
equals(res.borderTopWidth, "2px","border top");
equals(res.display, "block","display");
equals(res.cssFloat, "left","float");
equals(res.marginTop, "10px","margin top");
equals(res.paddingLeft, "5px","padding left");
equals(res.position, "relative","position");
$("#qunit-test-area").html("")
});
})
<html>
<head>
<title>CurStyles Test Suite</title>
<link rel="stylesheet" type="text/css" href="../../../funcunit/qunit/qunit.css" />
<style>
body {
margin: 0px; padding: 0px;
}
</style>
<script type='text/javascript' src='../../../steal/steal.js?jquery/dom/cur_styles/cur_styles_test.js'></script>
</head>
<body>
<h1 id="qunit-header">CurStyles Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<div id="test-content"></div>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
</body>
</html>
\ No newline at end of file
<div style='margin-top: 10px; padding-left: 5px; position: relative; float: left; border: solid 2px black;' id='styled'>
Here is some content;
</div>
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Dimensions Demo</title>
<style type='text/css'>
body {font-family: verdana}
#inner {
height: 100%;
width: 100%;
background-color: red;
}
#block {
height: 200px;
width: 200px;
padding: 0 40px 40px 0;
margin: 0 10px 10px 0;
background-color: blue;
border-right: solid 20px green;
border-bottom: solid 20px green;
}
#wrapper {
border: dashed 1px gray;
float: left;
clear: left;
background-color: yellow;
}
#width { background-color: red;}
#paddingRight {background-color: blue;}
#borderRightWidth {background-color: green;}
#innerWidth {color: #000080;}
#outerWidth {color: #008000;}
#marginRight {background-color: yellow}
input {
text-align: right;
font-size: 14pt;
font-weight: bold;
width: 100px;
}
label {
display: inline-block;
width: 100px;
text-align: right;
}
</style>
</head>
<body>
<div id="demo-html">
<p>Adjust The red box's layout properties.</p>
<label> Width</label> <input id='width'/><br/>
<label>+ Padding </label> <input id='paddingRight'/><br/>
<label>= Inner</label> <input id='innerWidth'/><br/>
<label>+ Border</label> <input id='borderRightWidth'/><br/>
<label>= Outer</label> <input id='outerWidth'/><br/>
<label> Margin</label> <input id='marginRight'/><br/>
<br/>
<div id='wrapper'>
<div id='block'>
<div id='inner'>
Adjust My Layout Properties
</div>
</div>
</div>
</div>
<div style='clear:both'></div>
<script type='text/javascript'
src='../../../steal/steal.js'>
</script>
<script type='text/javascript' id="demo-source">
steal('jquery/dom/dimensions').then(function(){
// sets the values in the input boxes
var set = function() {
var block = $('#block');
//get with .fn helpers
$("#outerWidth, #innerWidth, #width").each(function(){
$(this).val( block[this.id]() )
})
//use curStyles
$.each($('#block').curStyles("paddingRight",
"borderRightWidth",
"marginRight"), function(name, val){
$("#"+name).val( parseInt(val) )
});
}
set();
// updates the dimensions of the block
var update = function( ev ) {
var name = ev.target.id,
val = parseInt( $(ev.target).val() ),
opposite = {Width: "Height", Right: "Bottom"},
// the opposite dimension name
otherName = name.replace(/width|right/i, function(part, i){
return i == 0 ? "height" : opposite[part];
}),
block = $('#block'),
css = {};
if( block[name] ) {
// set with innerHeight, outerHeight, etc
block[name]( val )[otherName](val)
}else{
// set as css property
css[name] = val+"px"
css[otherName] = val+"px"
block.css(css)
}
set();
};
// call update on change or after
// typing has stopped for a second
var timer;
$("input").live('change',update)
$("input").live('keyup',function(ev) {
clearTimeout(timer)
timer = setTimeout(function() {
update(ev)
},1400)
})
})
</script>
</body>
</html>
\ No newline at end of file
steal('jquery/dom/cur_styles').then(function($) {
/**
* @page dimensions dimensions
* @parent dom
* @plugin jquery/dom/dimensions
*
* The dimensions plugin adds support for setting+animating inner+outer height and widths.
*
* ### Quick Examples
*
* $('#foo').outerWidth(100).innerHeight(50);
* $('#bar').animate({outerWidth: 500});
*
* ## Use
*
* When writing reusable plugins, you often want to
* set or animate an element's width and height that include its padding,
* border, or margin. This is especially important in plugins that
* allow custom styling.
*
* The dimensions plugin overwrites [jQuery.fn.outerHeight outerHeight],
* [jQuery.fn.outerWidth outerWidth], [jQuery.fn.innerHeight innerHeight]
* and [jQuery.fn.innerWidth innerWidth]
* to let you set and animate these properties.
*
*
*
*
* ## Demo
*
* @demo jquery/dom/dimensions/dimensions.html
*/
var weird = /button|select/i, //margin is inside border
getBoxes = {},
checks = {
width: ["Left", "Right"],
height: ['Top', 'Bottom'],
oldOuterHeight: $.fn.outerHeight,
oldOuterWidth: $.fn.outerWidth,
oldInnerWidth: $.fn.innerWidth,
oldInnerHeight: $.fn.innerHeight
};
/**
* @add jQuery.fn
*/
$.each({
/**
* @function outerWidth
* @parent dimensions
* Lets you set the outer width on an object
* @param {Number} [height]
* @param {Boolean} [includeMargin=false] Makes setting the outerWidth adjust
* for margin. Defaults to false.
*
* $('#hasMargin').outerWidth(50, true);
*
* @return {jQuery|Number} If you are setting the value, returns the jQuery wrapped elements.
*/
width:
/**
* @function innerWidth
* @parent dimensions
* Lets you set the inner height of an object
* @param {Number} [height]
*/
"Width",
/**
* @function outerHeight
* @parent dimensions
* Lets you set the outer height of an object where: <br/>
* <code>outerHeight = height + padding + border + (margin)</code>.
* @codestart
* $("#foo").outerHeight(100); //sets outer height
* $("#foo").outerHeight(100, true); //uses margins
* $("#foo").outerHeight(); //returns outer height
* $("#foo").outerHeight(true); //returns outer height with margins
* @codeend
* When setting the outerHeight, it adjusts the height of the element.
* @param {Number|Boolean} [height] If a number is provided -> sets the outer height of the object.<br/>
* If true is given -> returns the outer height and includes margins.<br/>
* If no value is given -> returns the outer height without margin.
* @param {Boolean} [includeMargin] Makes setting the outerHeight adjust for margin.
* @return {jQuery|Number} If you are setting the value, returns the jQuery wrapped elements.
* Otherwise, returns outerHeight in pixels.
*/
height:
/**
* @function innerHeight
* @parent dimensions
* Lets you set the outer width on an object
* @param {Number} [height]
*/
"Height" }, function(lower, Upper) {
//used to get the padding and border for an element in a given direction
getBoxes[lower] = function(el, boxes) {
var val = 0;
if (!weird.test(el.nodeName)) {
//make what to check for ....
var myChecks = [];
$.each(checks[lower], function() {
var direction = this;
$.each(boxes, function(name, val) {
if (val)
myChecks.push(name + direction+ (name == 'border' ? "Width" : "") );
})
})
$.each($.curStyles(el, myChecks), function(name, value) {
val += (parseFloat(value) || 0);
})
}
return val;
}
//getter / setter
$.fn["outer" + Upper] = function(v, margin) {
var first = this[0];
if (typeof v == 'number') {
first && this[lower](v - getBoxes[lower](first, {padding: true, border: true, margin: margin}))
return this;
} else {
return first ? checks["oldOuter" + Upper].call(this, v) : null;
}
}
$.fn["inner" + Upper] = function(v) {
var first = this[0];
if (typeof v == 'number') {
first&& this[lower](v - getBoxes[lower](first, { padding: true }))
return this;
} else {
return first ? checks["oldInner" + Upper].call(this, v) : null;
}
}
//provides animations
var animate = function(boxes){
return function(fx){
if (fx.state == 0) {
fx.start = $(fx.elem)[lower]();
fx.end = fx.end - getBoxes[lower](fx.elem,boxes);
}
fx.elem.style[lower] = (fx.pos * (fx.end - fx.start) + fx.start) + "px"
}
}
$.fx.step["outer" + Upper] = animate({padding: true, border: true})
$.fx.step["outer" + Upper+"Margin"] = animate({padding: true, border: true, margin: true})
$.fx.step["inner" + Upper] = animate({padding: true})
})
})
steal("jquery/dom/dimensions",
'jquery/view/micro',
'funcunit/qunit').then(function(){
module("jquery/dom/dimensions");
test("outerHeight and width",function(){
$("#qunit-test-area").html("//jquery/dom/dimensions/test/curStyles.micro",{})
})
});
\ No newline at end of file
<html>
<head>
<title>Dimensions Test Suite</title>
<link rel="stylesheet" type="text/css" href="../../../funcunit/qunit/qunit.css" />
<style>
body {
margin: 0px; padding: 0px;
}
</style>
<script type='text/javascript' src='../../../steal/steal.js?jquery/dom/dimensions/dimensions_test.js'></script>
</head>
<body>
<h1 id="qunit-header">Dimensions Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<div id="test-content"></div>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
</body>
</html>
\ No newline at end of file
<div style='margin-top: 10px; padding-left: 5px; position: relative; float: left; border: solid 2px black;' id='styled'>
Here is some content;
</div>
\ No newline at end of file
/**
@page dom DOM Helpers
@parent jquerymx
@description jQuery DOM extension.
JavaScriptMVC adds a bunch of useful
jQuery extensions for the dom. Check them out on the left.
## [dimensions Dimensions]
Set and animate the inner and outer height and width of elements.
$('#foo').outerWidth(100);
$('#bar').animate({innerWidth: 500});
This is great when you want to include padding and margin in
setting the dimensions of elements.
## [jQuery.cookie Cookie]
Set and get cookie values:
$.cookie('cookie','value');
## [jQuery.fixture Fixture]
Simulate Ajax responses.
$.fixture("/services/tasks.php','fixtures/tasks.json');
Works with jQuery's Ajax converters!
## [jQuery.fn.compare Compare]
Compare the location of two elements rapidly.
$('#foo').compare($('#bar')) & 2 // true if #bar is before #foo
## [jQuery.fn.curStyles CurStyles]
Get multiple css properties quickly.
$('#foo').curStyles('left','top') //-> {left:'20px',top:'10px'}
## [jQuery.fn.formParams FormParams]
Serializes a form into a JSON-like object:
$('form').formParams() //-> {name: 'Justin', favs: ['JS','Ruby']}
## [jQuery.fn.selection Selection]
Gets or sets the current text selection.
// gets selection info
$('pre').selection() //-> {start: 22, end: 57, range: range}
// sets the selection
$('div').selection(20,22)
## [jQuery.fn.within Within]
Returns elements that have a point within their boundaries.
$('.drop').within(200,200) //-> drops that touch 200,200
## [jQuery.Range Range]
Text range utilities.
$('#copy').range() //-> text range that has copy selected
## [jQuery.route]
Hash routes mapped to an [jQuery.Observe $.Observe].
$.route(':type',{type: 'videos'})
$.route.delegate('type','set', function(){ ... })
$.route.attr('type','images');
*/
steal('jquery');
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Fixture Demo</title>
<style type='text/css'>
body {font-family: verdana}
#messages {height: 200px; overflow-y: auto;}
#content {height: 551px; overflow: hidden;}
</style>
</head>
<body>
<div id="demo-html">
<div id='content'></div>
</div>
<script type='text/javascript'
src='../../../steal/steal.js'></script>
<script type='text/javascript' id="demo-source">
steal('jquery/dom/fixture',
'jquery/dom/form_params',
function(){
$.fixture("/messages.php",
'fixtures/messages.html')
// gets content from a fixture
$.get("/messages.php",
function(html){
// put the result in content
$('#content').html(html)
},
'text');
// makes 20 messages in a fixture
$.fixture.make(["messages","message"],20, function(i, messages){
return {
subject: "This is message "+i,
body: "Here is some text for this message",
user: "Justin",
createdAt: String(new Date( Math.random() * new Date().getTime() ))
}
});
// gets messages on submit
$("#getMessages").live("submit",function(ev){
ev.preventDefault();
//get the limit and offset
var params = $(this).formParams().params;
//use -messages fixture created by make
$.ajax({
url: "/messages.json",
data: params,
success: function(json){
$("#messages").html( messagesHTML(json) )
},
dataType: "json",
fixture: "-messages"
})
});
// a fixture for creating messages
$.fixture["-createMessage"] = function(settings, cbType){
// add to the message data what the server would add
var message = $.extend({
id: arguments.callee.count++,
user: "Justin",
createdAt: String(new Date())
}, settings.data);
message.id = $.fixture["~messages"].length;
// adds the message to the fixture data
$.fixture["~messages"].push(message);
// return the data for the callback
return [message];
};
// creates a message on submit
$("#message").live("submit", function(ev){
ev.preventDefault();
// get message data
var message = $(this).formParams().message;
// uses -createMessage fixture
$.post("/message.json", message,function(json){
//clear the message form
$('[name*=message]').val("");
//show the new message
$('[name*=offset]').val(json.id)
$('[name*=limit]').val(1)
$("#getMessages").submit();
},'json',"-createMessage")
})
//creates the html from message data
var messagesHTML = function(json){
var html = ["<h4>Messages (count=",
json.count,
")</h4>",
"<table>",
"<tr>"],
cols = ["subject",
"body",
"user",
"createdAt"];
// html for the column headers
$.each(cols, function(i, prop){
html.push("<th>"+prop+"</th>")
})
html.push("</tr>")
// html for the messages
$.each(json.data, function(m, message){
html.push("<tr>")
$.each(cols, function(i, prop){
html.push("<td>"+message[prop]+"</td>")
})
html.push("</tr>")
})
html.push("</table>");
return html.join("");
}
});
</script>
</body>
</html>
\ No newline at end of file
<h2>Create a Message</h2>
<p>Create a message, it will show up in "Get Messages".</p>
<form id='message'>
<table>
<tr>
<td>From:</td>
<td><input type='text' name='message[user]' value=''/></td>
</tr>
<tr>
<td>Subject:</td>
<td><input type='text' name='message[subject]' value=''/></td>
</tr>
<tr>
<td>Body:</td>
<td><textarea name='message[body]'></textarea></td>
</tr>
<tr>
<td></td><td><input type='submit' value="Create"></td>
</tr>
</table>
</form>
<h2>Get Messages</h2>
<p>Enter a limit and offset to get a range of messages.
</p>
<form id='getMessages'>
Offset <input type='text' name='params[offset]' value='0'/>
Limit <input type='text' name='params[limit]' value='5'/>
<input type="submit" value="Get Messages"/>
</form>
<div id='messages'></div>
<html>
<head>
<title>Fixtures Test Suite</title>
<link rel="stylesheet" type="text/css" href="../../../funcunit/qunit/qunit.css" />
<style>
body {
margin: 0px; padding: 0px;
}
</style>
<script type='text/javascript' src='../../../steal/steal.js?jquery/dom/fixture/fixture_test.js'></script>
</head>
<body>
<h1 id="qunit-header">Fixtures Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<div id="test-content"></div>
<ol id="qunit-tests"></ol>
<div id="qunit-test-area"></div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<title>Form Params</title>
<style type='text/css'>
body {font-family: verdana}
</style>
</head>
<body>
<p>Change the inputs to change the object</p>
<pre>Result = <span id='result'></span></pre>
<div id="demo-html">
<form id='fp' action="">
<label>People Count</label><br/>
<input name='talk[peopleCount]'/><br/>
<label>Audience Rating</label><br/>
<select name='talk[audienceRating]'>
<option value='3'>3</option>
<option value='2'>2</option>
<option value='1'>1</option>
</select><br/>
<label>Time Left</label><br/>
<input type='radio' name='talk[timeLeft]' value='1'/> 1 min<br/>
<input type='radio' name='talk[timeLeft]' value='5'/> 5 min<br/>
<input type='radio' name='talk[timeLeft]' value='10'/> 10 min<br/>
</form>
</div>
<script type='text/javascript'
src='../../../steal/steal.js'>
</script>
<script type='text/javascript' id="demo-source">
steal('jquery/dom/form_params','jquery/lang/json').then(function(){
// updates the JSON text
var update = function(){
// get form data
var json = $('#fp').formParams(),
//convert it to JSON
jsonString = $.toJSON( json );
// show JSON
$("#result").text( jsonString )
}
// listen for changes and update
$('#fp').change(update);
// show json right away
update();
})
</script>
</body>
</html>
\ No newline at end of file
<form id='fp' action="">
<input type='checkbox' name='foo' value='true'/>
<input type='checkbox' name='wrong' checked="checked" value='false' />
<input type='checkbox' name='bar[abc]' checked="checked" value='true'/>
<input type='checkbox' name='bar[def]' checked="checked" value='true'/>
<input type='checkbox' name='bar[ghi]' value='true'/>
</form>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment