MINOR Upgraded jQuery.entwine (formerly known as jQuery.concrete) to the latest trunk
MINOR Updated jQuery.concrete references to point to the new "entwine" name git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@102695 467b73ca-7a2a-4603-9d3b-597d59a354a9
@ -28,7 +28,7 @@ class CalendarDateField extends DateField {
|
||||
}
|
||||
|
||||
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-concrete/dist/jquery.concrete-dist.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-entwine/dist/jquery.entwine-dist.js');
|
||||
|
||||
// javascript: custom
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/CalendarDateField.js');
|
||||
|
@ -58,7 +58,7 @@ class TabSet extends CompositeField {
|
||||
Requirements::css(SAPPHIRE_DIR . '/thirdparty/jquery-ui-themes/smoothness/ui.all.css');
|
||||
Requirements::css(SAPPHIRE_DIR . '/thirdparty/jquery-ui-themes/smoothness/ui.tabs.css');
|
||||
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-concrete/dist/jquery.concrete-dist.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-entwine/dist/jquery.entwine-dist.js');
|
||||
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/TabSet.js');
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
(function($) {
|
||||
$.concrete('ss', function($){
|
||||
$.entwine('ss', function($){
|
||||
/**
|
||||
* Formats a <input type="text"> field with a jQuery UI datepicker.
|
||||
*
|
||||
@ -7,7 +7,7 @@
|
||||
*
|
||||
* @author Ingo Schommer, SilverStripe Ltd.
|
||||
*/
|
||||
$('.calendardate').concrete({
|
||||
$('.calendardate').entwine({
|
||||
onmatch: function() {
|
||||
this.find('input').each(function() {
|
||||
var conf = $(this).metadata();
|
||||
|
@ -1,5 +1,5 @@
|
||||
(function($){
|
||||
$.concrete('ss', function($){
|
||||
$.entwine('ss', function($){
|
||||
/**
|
||||
* Lightweight wrapper around jQuery UI tabs.
|
||||
* Ensures that anchor links are set properly,
|
||||
@ -7,7 +7,7 @@
|
||||
* their height explicitly set. This is important
|
||||
* for forms inside the CMS layout.
|
||||
*/
|
||||
$('.ss-tabset').concrete({
|
||||
$('.ss-tabset').entwine({
|
||||
onmatch: function() {
|
||||
this.rewriteHashlinks();
|
||||
|
||||
|
@ -349,7 +349,7 @@ class Security extends Controller {
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-ui/ui.core.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-ui/ui.tabs.js');
|
||||
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-concrete/dist/jquery.concrete-dist.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-entwine/dist/jquery.entwine-dist.js');
|
||||
|
||||
Requirements::css(THIRDPARTY_DIR . '/jquery/themes/smoothness/ui.all.css');
|
||||
Requirements::css(THIRDPARTY_DIR . '/jquery/themes/smoothness/ui.tabs.css');
|
||||
|
BIN
thirdparty/jquery-concrete/.DS_Store
vendored
2
thirdparty/jquery-concrete/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
vendor/
|
||||
spec/
|
8
thirdparty/jquery-concrete/.piston.yml
vendored
@ -1,8 +0,0 @@
|
||||
---
|
||||
format: 1
|
||||
handler:
|
||||
commit: bae4684bd5ab659bd78ebd990cc68ecba8a36669
|
||||
branch: master
|
||||
lock: false
|
||||
repository_class: Piston::Git::Repository
|
||||
repository_url: git://github.com/hafriedlander/jquery.concrete.git
|
@ -1,77 +0,0 @@
|
||||
(function($) {
|
||||
|
||||
var concrete_prepend = '__concrete!';
|
||||
|
||||
var getConcreteData = function(el, namespace, property) {
|
||||
return el.data(concrete_prepend + namespace + '!' + property);
|
||||
}
|
||||
|
||||
var setConcreteData = function(el, namespace, property, value) {
|
||||
return el.data(concrete_prepend + namespace + '!' + property, value);
|
||||
}
|
||||
|
||||
var getConcreteDataAsHash = function(el, namespace) {
|
||||
var hash = {};
|
||||
var id = jQuery.data(el[0]);
|
||||
|
||||
var matchstr = concrete_prepend + namespace + '!';
|
||||
var matchlen = matchstr.length;
|
||||
|
||||
var cache = jQuery.cache[id];
|
||||
for (var k in cache) {
|
||||
if (k.substr(0,matchlen) == matchstr) hash[k.substr(matchlen)] = cache[k];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
var setConcreteDataFromHash = function(el, namespace, hash) {
|
||||
for (var k in hash) setConcreteData(namespace, k, hash[k]);
|
||||
}
|
||||
|
||||
var concreteData = function(el, namespace, args) {
|
||||
switch (args.length) {
|
||||
case 0:
|
||||
return getConcreteDataAsHash(el, namespace);
|
||||
case 1:
|
||||
if (typeof args[0] == 'string') return getConcreteData(el, namespace, args[0]);
|
||||
else return setConcreteDataFromHash(el, namespace, args[0]);
|
||||
default:
|
||||
return setConcreteData(el, namespace, args[0], args[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$.extend($.fn, {
|
||||
concreteData: function() {
|
||||
return concreteData(this, '__base', arguments);
|
||||
}
|
||||
});
|
||||
|
||||
$.concrete.Namespace.addHandler({
|
||||
order: 60,
|
||||
|
||||
bind: function(selector, k, v) {
|
||||
if (k.charAt(0) != k.charAt(0).toUpperCase()) $.concrete.warn('Concrete property '+k+' does not start with a capital letter', $.concrete.WARN_LEVEL_BESTPRACTISE);
|
||||
|
||||
var namespace = this;
|
||||
g = function() { return this.concreteData(k) || v ; }
|
||||
s = function(v){ return this.concreteData(k, v); }
|
||||
|
||||
g.pname = s.pname = k;
|
||||
|
||||
this.bind_proxy(selector, 'get'+k, g);
|
||||
this.bind_proxy(selector, 'set'+k, s);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
namespaceMethodOverrides: function(namespace){
|
||||
return {
|
||||
concreteData: function() {
|
||||
return concreteData(this, namespace.name, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
114
thirdparty/jquery-concrete/src/jquery.dat.js
vendored
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Provides a per-node data store that is automatically cloned when dom node is clone() or cloneNode()'d.
|
||||
*/
|
||||
|
||||
(function($){
|
||||
var data_store = {};
|
||||
var check_name = 'com.silverstripe:check_id';
|
||||
|
||||
var expando = 'data_id:';
|
||||
var id = 0;
|
||||
|
||||
/**
|
||||
* Clone a data object. Currently uses jQuery's deep copy routine
|
||||
*/
|
||||
var cloneData = function(data) {
|
||||
return $.extend(true, {}, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data object for an element.
|
||||
* Picks a new ID, sets the tracking attribute and value on the DOM node and stores data in the data_store
|
||||
*
|
||||
* @param {jQuery selection} el - The element to store this data on
|
||||
* @param {Object} data - The object to use as data, or undefined / null for an empty object
|
||||
*/
|
||||
var setData = function(el, data) {
|
||||
if (!data) data = {};
|
||||
|
||||
id += 1;
|
||||
var data_id = expando + id;
|
||||
|
||||
el.attr('data', data_id); el.data(check_name, data_id);
|
||||
return data_store[data_id] = data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete the data object for an element
|
||||
* It's important this is called when the related element is deled, or memory could leak. We monkey-patch jQuery.removeData to make sure this happens
|
||||
* @param {jQuery selection} el - The element to remove the data for
|
||||
*/
|
||||
var clearData = function(el) {
|
||||
var data_id = el.attr('data');
|
||||
if (!data_id) return;
|
||||
|
||||
el.removeAttr('data');
|
||||
// Only remove the data if this is the last element with a data reference to it. This is so removing an element
|
||||
// doesn't delete the data before any cloned elements have a chance to copy it
|
||||
if ($('[data='+data_id+']').length == 0) delete data_store[data_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data object for an element
|
||||
* Sets an empty data object if the element does not have one yet
|
||||
* Clones the data object if the element it's attached to has been cloned
|
||||
* @param {jQuery selection} el - The element to retrieve the data of
|
||||
*/
|
||||
var getData = function(el) {
|
||||
// If the data_id is missing, the element has no data
|
||||
var data_id = el.attr('data');
|
||||
if (!data_id) return setData(el);
|
||||
|
||||
var check_id = el.data(check_name);
|
||||
if (!check_id || check_id != data_id) {
|
||||
// If the check_id is missing, the element has been cloned. So clone the data too
|
||||
var newdata = cloneData(data_store[data_id]);
|
||||
setData(el, newdata);
|
||||
// If we were the last element holding on to a reference to that old data, delete it now that we're done with it
|
||||
if ($('[data='+data_id+']').length == 0) delete data_store[data_id];
|
||||
return newdata;
|
||||
}
|
||||
|
||||
// Otherwise, this element has some data, so return it
|
||||
return data_store[data_id];
|
||||
}
|
||||
|
||||
$.dat = {};
|
||||
/**
|
||||
* Check all data in data_store, removing any that are not longer referenced in the DOM
|
||||
* Returns number of garbage-collected entries, for finding memory leaks
|
||||
*/
|
||||
$.dat.vacuum = function() {
|
||||
var i = 0;
|
||||
for (var k in data_store) {
|
||||
if ($('[data='+k+']').length == 0) { delete data_store[k]; i++; }
|
||||
}
|
||||
return i;
|
||||
}
|
||||
/**
|
||||
* Return count of items in data_store.
|
||||
* Used in tests
|
||||
*/
|
||||
$.dat.size = function() {
|
||||
var i = 0;
|
||||
for (var k in data_store) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data object for the current element
|
||||
*/
|
||||
$.fn.d = function(a){
|
||||
return getData(this.eq(0));
|
||||
};
|
||||
|
||||
// Monkey patch removeData to also remove dat
|
||||
var removeData_without_dat = $.removeData
|
||||
$.removeData = function(elem, name) {
|
||||
if (!name) clearData($(elem));
|
||||
return removeData_without_dat.apply(this, arguments);
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
|
8
thirdparty/jquery-entwine/.piston.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
format: 1
|
||||
handler:
|
||||
commit: f09e97da777031a67e136945f8732890c84e3e65
|
||||
branch: master
|
||||
lock: false
|
||||
repository_class: Piston::Git::Repository
|
||||
repository_url: git://github.com/hafriedlander/jquery.entwine.git
|
@ -1,25 +1,29 @@
|
||||
h1. Concrete - Support for ConcreteUI programming in jQuery
|
||||
h1. Entwine - Support for Concrete UI style programming in jQuery
|
||||
|
||||
By Hamish Friedlander, with thanks to "SilverStripe":http://www.silverstripe.com/
|
||||
|
||||
Concrete tries to provide a new model of code organisation - a replacement for Object Oriented programming that is focused on adding functions to groups of DOM elements based on the structure and contents of those DOM elements. It's a merging of the model and view layer that initially seems weird, but can give very powerful results.
|
||||
Entwine tries to provide a new model of code organisation - a replacement for Object Oriented programming that is focused on adding functions to groups of DOM elements based on the structure and contents of those DOM elements. It's a merging of the model and view layer that initially seems weird, but can give very powerful results.
|
||||
|
||||
We're standing on the shoulders of giants here - combining ideas from Prototype's behaviour & lowpro and jQuery's effen & livequery (who themselves stole ideals from Self's Morphic UI and others), but extending & combining the concepts presented in those tools to provide a complete alternative to traditional OO concepts - self-aware methods, inheritance, polymorphisim and namespacing without a single class definition.
|
||||
|
||||
h2. Getting Started
|
||||
|
||||
* Walk through the "Tutorial":http://hafriedlander.github.com/jquery.concrete/tutorial/
|
||||
* Walk through the "Tutorial":http://hafriedlander.github.com/jquery.entwine/tutorial/
|
||||
* Watch the "Screencast":http://www.vimeo.com/6353390 (shot during a introductory developer meeting at SilverStripe)
|
||||
* Join the "Google Group":http://groups.google.com/group/jquery-concrete and let us know what you think, or what other features you'd like to see
|
||||
* Join the "Google Group":http://groups.google.com/group/jquery-entwine and let us know what you think, or what other features you'd like to see
|
||||
|
||||
h2. Name change
|
||||
|
||||
jQuery Entwine used to be called jQuery Concrete. The name was changed to avoid confusion with another product. The concrete function remains as an alias, but all new code should use entwine
|
||||
|
||||
h2. Basic use
|
||||
|
||||
h4. First intro
|
||||
|
||||
To attach methods to DOM nodes, call the `concrete` function on a jQuery selector object, passing a hash listing the method names and bodys
|
||||
To attach methods to DOM nodes, call the `entwine` function on a jQuery selector object, passing a hash listing the method names and bodys
|
||||
|
||||
<pre><code>
|
||||
$('div').concrete({
|
||||
$('div').entwine({
|
||||
foo: function(..){..},
|
||||
bar: function(..){..}
|
||||
});
|
||||
@ -46,13 +50,13 @@ Given this DOM structure:
|
||||
</body>
|
||||
</code></pre>
|
||||
|
||||
And this concrete definition
|
||||
And this entwine definition
|
||||
|
||||
<pre><code>
|
||||
$('.internal_text').concrete({
|
||||
$('.internal_text').entwine({
|
||||
foo: function(){ console.log(this.text()); }
|
||||
});
|
||||
$('.attribute_text').concrete({
|
||||
$('.attribute_text').entwine({
|
||||
foo: function(){ console.log(this.attr('rel')); }
|
||||
});
|
||||
</code></pre>
|
||||
@ -72,12 +76,12 @@ Will log this to the console
|
||||
|
||||
h4. Limitations
|
||||
|
||||
When defining methods, the jQuery object that concrete is called on must be a plain selector, without context. These examples will not work
|
||||
When defining methods, the jQuery object that entwine is called on must be a plain selector, without context. These examples will not work
|
||||
|
||||
<pre><code>
|
||||
$('div', el).concrete(...)
|
||||
$([ela, elb, elc]).concrete(...)
|
||||
$('<div id="a"></div>').concrete(...)
|
||||
$('div', el).entwine(...)
|
||||
$([ela, elb, elc]).entwine(...)
|
||||
$('<div id="a"></div>').entwine(...)
|
||||
</code></pre>
|
||||
|
||||
h2. Live
|
||||
@ -100,13 +104,13 @@ Another example. Given this DOM structure
|
||||
</body>
|
||||
</code></pre>
|
||||
|
||||
And this concrete definition
|
||||
And this entwine definition
|
||||
|
||||
<pre><code>
|
||||
$('div').concrete({
|
||||
$('div').entwine({
|
||||
foo: function(){ console.log(this.text()); }
|
||||
});
|
||||
$('.attribute_text').concrete({
|
||||
$('.attribute_text').entwine({
|
||||
foo: function(){ console.log(this.attr('rel')); }
|
||||
});
|
||||
</code></pre>
|
||||
@ -134,10 +138,10 @@ name. Just like other functions this binding will be live, and only the most spe
|
||||
<head>
|
||||
<script type='text/javascript'>
|
||||
/* No need for onready wrapper. Events are bound as needed */
|
||||
$('div').concrete({
|
||||
$('div').entwine({
|
||||
onclick: function(){ this.css({backgroundColor: 'blue'}); }
|
||||
});
|
||||
$('.green').concrete({
|
||||
$('.green').entwine({
|
||||
onclick: function(){ this.css({color: 'green'}); }
|
||||
});
|
||||
</script>
|
||||
@ -153,7 +157,7 @@ h2. Constructors / Destructors
|
||||
Declaring a function with the name `onmatch` will create a behavior that is called on each object when it matches. Likewise, `onunmatch` will
|
||||
be called when an object that did match this selector stops matching it (because it is removed, or because you've changed its properties).
|
||||
|
||||
Note that an onunmatch block must be paired with an onmatch block - an onunmatch without an onmatch _in the same concrete definition block_ is illegal
|
||||
Note that an onunmatch block must be paired with an onmatch block - an onunmatch without an onmatch _in the same entwine definition block_ is illegal
|
||||
|
||||
Like other functions, only the most specific definition will be used. However, because property changes are not atomic, this may not work as you
|
||||
expect.
|
||||
@ -163,8 +167,8 @@ h2. Namespaces
|
||||
To avoid name clashes, to allow multiple bindings to the same event, and to generally seperate a set of functions from other code you can use namespaces
|
||||
|
||||
<pre><code>
|
||||
$.concrete('foo.bar', function($){
|
||||
$('div').concrete({
|
||||
$.entwine('foo.bar', function($){
|
||||
$('div').entwine({
|
||||
baz: function(){}
|
||||
});
|
||||
});
|
||||
@ -173,19 +177,19 @@ To avoid name clashes, to allow multiple bindings to the same event, and to gene
|
||||
You can then call these functions like this:
|
||||
|
||||
<pre><code>
|
||||
$('div').concrete('foo.bar').baz()
|
||||
$('div').entwine('foo.bar').baz()
|
||||
</code></pre>
|
||||
|
||||
Namespaced functions work just like regular functions (`this` is still set to a matching DOM Node). However, specifity is calculated per namespace.
|
||||
This is particularly useful for events, because given this:
|
||||
|
||||
<pre><code>
|
||||
$('div').concrete({
|
||||
$('div').entwine({
|
||||
onclick: function(){ this.css({backgroundColor: 'blue'}); }
|
||||
});
|
||||
|
||||
$.concrete('foo', function($){
|
||||
$('div').concrete({
|
||||
$.entwine('foo', function($){
|
||||
$('div').entwine({
|
||||
onclick: function(){ this.css({color: 'green'}); }
|
||||
});
|
||||
});
|
||||
@ -203,14 +207,14 @@ Inside a namespace definition, functions remember the namespace they are in, and
|
||||
Where they don't exist, they will be looked up in the base namespace
|
||||
|
||||
<pre><code>
|
||||
$.concrete('foo', function($){
|
||||
$('div').concrete({
|
||||
$.entwine('foo', function($){
|
||||
$('div').entwine({
|
||||
bar: function() { this.baz(); this.qux(); }
|
||||
baz: function() { console.log('baz'); }
|
||||
})
|
||||
})
|
||||
|
||||
$('div').concrete({
|
||||
$('div').entwine({
|
||||
qux: function() { console.log('qux'); }
|
||||
})
|
||||
</code></pre>
|
||||
@ -223,20 +227,20 @@ Note that 'exists' means that a function is declared in this namespace for _any_
|
||||
<div>Internal text</div>
|
||||
</code></pre>
|
||||
|
||||
And the concrete definitions
|
||||
And the entwine definitions
|
||||
|
||||
<pre><code>
|
||||
$.concrete('foo', function($){
|
||||
$('div').concrete({
|
||||
$.entwine('foo', function($){
|
||||
$('div').entwine({
|
||||
bar: function() { this.baz(); }
|
||||
});
|
||||
$('span').concrete({
|
||||
$('span').entwine({
|
||||
baz: function() { console.log('a'); }
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
$('div').concrete({
|
||||
$('div').entwine({
|
||||
baz: function() { console.log('b'); }
|
||||
})
|
||||
</code></pre>
|
||||
@ -245,15 +249,15 @@ Then doing $('div').bar(); will _not_ display b. Even though the span rule could
|
||||
|
||||
h4. Nesting namespace blocks
|
||||
|
||||
You can also nest declarations. In this next example, we're defining the functions $().concrete('zap').bar() and $().concrete('zap.pow').baz()
|
||||
You can also nest declarations. In this next example, we're defining the functions $().entwine('zap').bar() and $().entwine('zap.pow').baz()
|
||||
|
||||
<pre><code>
|
||||
$.concrete('zap', function($){
|
||||
$('div').concrete({
|
||||
$.entwine('zap', function($){
|
||||
$('div').entwine({
|
||||
bar: function() { .. }
|
||||
})
|
||||
$.concrete('pow', function($){
|
||||
$('div').concrete({
|
||||
$.entwine('pow', function($){
|
||||
$('div').entwine({
|
||||
baz: function() { .. }
|
||||
})
|
||||
})
|
||||
@ -264,12 +268,12 @@ h4. Calling to another namespace (and forcing base)
|
||||
|
||||
Inside a namespace, namespace lookups are by default relative to the current namespace.
|
||||
|
||||
In some situations (such as the last example) you may want to force using the base namespace. In this case you can call concrete with the first argument being the base namespace code '.'. For example, if the first definition in the previous example was
|
||||
In some situations (such as the last example) you may want to force using the base namespace. In this case you can call entwine with the first argument being the base namespace code '.'. For example, if the first definition in the previous example was
|
||||
|
||||
<pre><code>
|
||||
$.concrete('foo', function($){
|
||||
$('div').concrete({
|
||||
bar: function() { this.concrete('.').baz(); }
|
||||
$.entwine('foo', function($){
|
||||
$('div').entwine({
|
||||
bar: function() { this.entwine('.').baz(); }
|
||||
})
|
||||
})
|
||||
</code></pre>
|
||||
@ -278,16 +282,16 @@ Then b _would_ be output to the console.
|
||||
|
||||
h4. Using
|
||||
|
||||
Sometimes a block outside of a namespace will need to refer to that namespace repeatedly. By passing a function to the concrete function, you can change the looked-up namespace
|
||||
Sometimes a block outside of a namespace will need to refer to that namespace repeatedly. By passing a function to the entwine function, you can change the looked-up namespace
|
||||
|
||||
<pre><code>
|
||||
$.concrete('foo', function($){
|
||||
$('div').concrete({
|
||||
$.entwine('foo', function($){
|
||||
$('div').entwine({
|
||||
bar: function() { console.log('a'); }
|
||||
})
|
||||
})
|
||||
|
||||
$('div').concrete('foo', function(){
|
||||
$('div').entwine('foo', function(){
|
||||
this.bar();
|
||||
this.bar();
|
||||
this.bar();
|
||||
@ -296,6 +300,36 @@ Sometimes a block outside of a namespace will need to refer to that namespace re
|
||||
|
||||
This equivalent to /with/ in javascript, and just like /with/, care should be taken to only use this construct in situations that merit it.
|
||||
|
||||
h2. Tests
|
||||
|
||||
Specs are written using the awesome "JSpec":http://github.com/visionmedia/jspec library. You can run them in two ways
|
||||
|
||||
h4. Ad-hoc
|
||||
|
||||
Open the file `spec/spec.html` in any modern browser
|
||||
|
||||
h4. Continuous testing
|
||||
|
||||
JSpec has a command line client which can be used for continuous testing. Make sure ruby is installed and enabled the "Gemcutter":http://gemcutter.org/ gem hosting service, like so:
|
||||
|
||||
<pre><code>
|
||||
sudo gem install gemcutter
|
||||
sudo gem tumble
|
||||
</code></pre>
|
||||
|
||||
Then install the jspec binary:
|
||||
|
||||
<pre><code>
|
||||
sudo gem install jspec
|
||||
</code></pre>
|
||||
|
||||
The JSpec command line tool should now be installed. This command will re-run the specs whenever you edit a file:
|
||||
|
||||
<pre><code>
|
||||
jspec spec/spec.html -p src,spec
|
||||
</code></pre>
|
||||
|
||||
|
||||
h2. License
|
||||
|
||||
Copyright (C) 2009 Hamish Friedlander (hamish@silverstripe.com) and SilverStripe Limited (www.silverstripe.com). All rights reserved.
|
@ -1,12 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Specify the output file's name
|
||||
FILE="dist/jquery.concrete-dist.js"
|
||||
FILE="dist/jquery.entwine-dist.js"
|
||||
|
||||
mkdir -p dist
|
||||
rm dist/*.js
|
||||
|
||||
echo "/* jQuery.Concrete - Copyright 2009 Hamish Friedlander and SilverStripe. Version $VER. */" > $FILE
|
||||
echo "/* jQuery.Entwine - Copyright 2009 Hamish Friedlander and SilverStripe. Version $VER. */" > $FILE
|
||||
|
||||
for x in \
|
||||
vendor/jquery.selector/jquery.class.js \
|
||||
@ -14,11 +14,12 @@ for x in \
|
||||
vendor/jquery.selector/jquery.selector.specifity.js \
|
||||
vendor/jquery.selector/jquery.selector.matches.js \
|
||||
src/jquery.focusinout.js \
|
||||
src/jquery.concrete.js \
|
||||
src/jquery.concrete.dommaybechanged.js \
|
||||
src/jquery.concrete.events.js \
|
||||
src/jquery.concrete.ctors.js \
|
||||
src/jquery.concrete.properties.js
|
||||
src/jquery.entwine.js \
|
||||
src/jquery.entwine.dommaybechanged.js \
|
||||
src/jquery.entwine.events.js \
|
||||
src/jquery.entwine.ctors.js \
|
||||
src/jquery.entwine.properties.js \
|
||||
src/jquery.entwine.legacy.js
|
||||
do \
|
||||
echo >> $FILE
|
||||
echo "/* $x */" >> $FILE
|
@ -1,4 +1,4 @@
|
||||
/* jQuery.Concrete - Copyright 2009 Hamish Friedlander and SilverStripe. Version . */
|
||||
/* jQuery.Entwine - Copyright 2009 Hamish Friedlander and SilverStripe. Version . */
|
||||
|
||||
/* vendor/jquery.selector/jquery.class.js */
|
||||
|
||||
@ -16,17 +16,18 @@ var Base;
|
||||
|
||||
(function(){
|
||||
|
||||
var marker = {}, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
var marker = {}, fnTest = /xyz/.test(function(){var xyz;}) ? /\b_super\b/ : /.*/;
|
||||
|
||||
// The base Class implementation (does nothing)
|
||||
Base = function(){};
|
||||
|
||||
Base.addMethod = function(name, func) {
|
||||
var _super = this._super;
|
||||
if (_super && fnTest.test(func)) {
|
||||
var parent = this._super && this._super.prototype;
|
||||
|
||||
if (parent && fnTest.test(func)) {
|
||||
this.prototype[name] = function(){
|
||||
var tmp = this._super;
|
||||
this._super = _super[name];
|
||||
this._super = parent[name];
|
||||
try {
|
||||
var ret = func.apply(this, arguments);
|
||||
}
|
||||
@ -34,17 +35,25 @@ var Base;
|
||||
this._super = tmp;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
else this.prototype[name] = func;
|
||||
}
|
||||
};
|
||||
|
||||
Base.addMethods = function(props) {
|
||||
for (var name in props) {
|
||||
if (typeof props[name] == 'function') this.addMethod(name, props[name]);
|
||||
else this.prototype[name] = props[name];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Base.subclassOf = function(parentkls) {
|
||||
var kls = this;
|
||||
while (kls) {
|
||||
if (kls === parentkls) return true;
|
||||
kls = kls._super;
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
Base.extend = function(props) {
|
||||
@ -59,18 +68,21 @@ var Base;
|
||||
else {
|
||||
var ret = new Kls(marker); if (ret.init) ret.init.apply(ret, arguments); return ret;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Add the common class variables and methods
|
||||
Kls.constructor = Kls;
|
||||
Kls.extend = Base.extend;
|
||||
Kls.addMethod = Base.addMethod;
|
||||
Kls.addMethods = Base.addMethods;
|
||||
Kls._super = this.prototype;
|
||||
Kls.subclassOf = Base.subclassOf;
|
||||
|
||||
Kls._super = this;
|
||||
|
||||
// Attach the parent object to the inheritance chain
|
||||
Kls.prototype = new this(marker);
|
||||
|
||||
Kls.prototype.constructor = Kls;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
Kls.addMethods(props);
|
||||
|
||||
@ -104,7 +116,7 @@ var Base;
|
||||
|
||||
WITHN: /([-+])?(INTEGER)?(n)\s*(?:([-+])\s*(INTEGER))?/,
|
||||
WITHOUTN: /([-+])?(INTEGER)/
|
||||
}
|
||||
};
|
||||
|
||||
var rx = {
|
||||
not: /:not\(/,
|
||||
@ -121,12 +133,12 @@ var Base;
|
||||
comb: /\s*(\+|~|>)\s*|\s+/,
|
||||
comma: /\s*,\s*/,
|
||||
important: /\s+!important\s*$/
|
||||
}
|
||||
};
|
||||
|
||||
/* Replace placeholders with actual regex, and mark all as case insensitive */
|
||||
var token = /[A-Z][A-Z0-9]+/;
|
||||
for (var k in rx) {
|
||||
var src = rx[k].source;
|
||||
var m, src = rx[k].source;
|
||||
while (m = src.match(token)) src = src.replace(m[0], tokens[m[0]].source);
|
||||
rx[k] = new RegExp(src, 'gi');
|
||||
}
|
||||
@ -160,7 +172,7 @@ var Base;
|
||||
done: function() {
|
||||
return this.pos == this.str.length;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
/* A base class that all Selectors inherit off */
|
||||
var SelectorBase = Base.extend({});
|
||||
@ -187,7 +199,7 @@ var Base;
|
||||
/* Then for each selection type, try and find a match */
|
||||
do {
|
||||
if (m = selector.match(rx.not)) {
|
||||
this.nots[this.nots.length] = SelectorsGroup().parse(selector)
|
||||
this.nots[this.nots.length] = SelectorsGroup().parse(selector);
|
||||
if (!(m = selector.match(rx.not_end))) {
|
||||
throw 'Invalid :not term in selector';
|
||||
}
|
||||
@ -213,7 +225,7 @@ var Base;
|
||||
|
||||
return this;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* A class representing a Selector, as per the CSS3 selector spec
|
||||
@ -261,14 +273,14 @@ var Base;
|
||||
|
||||
if (!cons.done()) throw 'Could not parse selector - ' + cons.showpos() ;
|
||||
else return res;
|
||||
}
|
||||
};
|
||||
|
||||
$.selector.SelectorBase = SelectorBase;
|
||||
$.selector.SimpleSelector = SimpleSelector;
|
||||
$.selector.Selector = Selector;
|
||||
$.selector.SelectorsGroup = SelectorsGroup;
|
||||
|
||||
})(jQuery)
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
@ -289,7 +301,7 @@ var Base;
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
})
|
||||
});
|
||||
|
||||
$.selector.Selector.addMethod('specifity', function(){
|
||||
if (this.spec) return this.spec;
|
||||
@ -301,7 +313,7 @@ var Base;
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
})
|
||||
});
|
||||
|
||||
$.selector.SelectorsGroup.addMethod('specifity', function(){
|
||||
if (this.spec) return this.spec;
|
||||
@ -312,7 +324,7 @@ var Base;
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
||||
@ -341,16 +353,16 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
// Does browser support Element.children
|
||||
var hasChildren = div.children && div.children[0].tagName == 'FORM';
|
||||
|
||||
var FUNC_IN = /^\s*function\s*\([^)]*\)\s*{/;
|
||||
var FUNC_IN = /^\s*function\s*\([^)]*\)\s*\{/;
|
||||
var FUNC_OUT = /}\s*$/;
|
||||
|
||||
var funcToString = function(f) {
|
||||
return (''+f).replace(FUNC_IN,'').replace(FUNC_OUT,'');
|
||||
}
|
||||
};
|
||||
|
||||
// Can we use Function#toString ?
|
||||
try {
|
||||
var testFunc = function(){ return 'good' };
|
||||
var testFunc = function(){ return 'good'; };
|
||||
if ((new Function('',funcToString(testFunc)))() != 'good') funcToString = false;
|
||||
}
|
||||
catch(e) { funcToString = false; console.log(e.message);/*pass*/ }
|
||||
@ -364,21 +376,26 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
|
||||
var join = function(js) {
|
||||
return js.join('\n');
|
||||
}
|
||||
};
|
||||
|
||||
var join_complex = function(js) {
|
||||
code = new String(js.join('\n')); // String objects can have properties set. strings can't
|
||||
var code = new String(js.join('\n')); // String objects can have properties set. strings can't
|
||||
code.complex = true;
|
||||
return code;
|
||||
}
|
||||
};
|
||||
|
||||
/**** ATTRIBUTE ACCESSORS ****/
|
||||
|
||||
// Not all attribute names can be used as identifiers, so we encode any non-acceptable characters as hex
|
||||
var varForAttr = function(attr) {
|
||||
return '_' + attr.replace(/^[^A-Za-z]|[^A-Za-z0-9]/g, function(m){ return '_0x' + m.charCodeAt(0).toString(16) + '_'; });
|
||||
};
|
||||
|
||||
var getAttr;
|
||||
|
||||
// Good browsers
|
||||
if (!getAttributeDodgy) {
|
||||
getAttr = function(attr){ return 'var _'+attr+' = el.getAttribute("'+attr+'");' ; }
|
||||
getAttr = function(attr){ return 'var '+varForAttr(attr)+' = el.getAttribute("'+attr+'");' ; };
|
||||
}
|
||||
// IE 6, 7
|
||||
else {
|
||||
@ -387,21 +404,21 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
|
||||
getAttr = function(attr) {
|
||||
var ieattr = getAttrIEMap[attr] || attr;
|
||||
return 'var _'+attr+' = el.getAttribute("'+ieattr+'",2) || (el.getAttributeNode("'+attr+'")||{}).nodeValue;';
|
||||
}
|
||||
return 'var '+varForAttr(attr)+' = el.getAttribute("'+ieattr+'",2) || (el.getAttributeNode("'+attr+'")||{}).nodeValue;';
|
||||
};
|
||||
}
|
||||
|
||||
/**** ATTRIBUTE COMPARITORS ****/
|
||||
|
||||
var attrchecks = {
|
||||
'-': '!_K',
|
||||
'=': '_K != "V"',
|
||||
'!=': '_K == "V"',
|
||||
'~=': '__K.indexOf(" V ") == -1',
|
||||
'^=': '!_K || _K.indexOf("V") != 0',
|
||||
'*=': '!_K || _K.indexOf("V") == -1',
|
||||
'$=': '!_K || _K.substr(_K.length-"V".length) != "V"'
|
||||
}
|
||||
'-': '!K',
|
||||
'=': 'K != "V"',
|
||||
'!=': 'K == "V"',
|
||||
'~=': '_WS_K.indexOf(" V ") == -1',
|
||||
'^=': '!K || K.indexOf("V") != 0',
|
||||
'*=': '!K || K.indexOf("V") == -1',
|
||||
'$=': '!K || K.substr(K.length-"V".length) != "V"'
|
||||
};
|
||||
|
||||
/**** STATE TRACKER ****/
|
||||
|
||||
@ -429,7 +446,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
return join([
|
||||
'while(el = el.previousSibling){',
|
||||
'if (el.nodeType != 1) continue;',
|
||||
body,
|
||||
body
|
||||
]);
|
||||
},
|
||||
parent: function() {
|
||||
@ -453,7 +470,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
uses_wsattr: function(attr) {
|
||||
if (this.wsattrs[attr]) return;
|
||||
this.wsattrs[attr] = true;
|
||||
return join([this.uses_attr(attr), 'var __'+attr+' = " "+_'+attr+'+" ";']);
|
||||
return join([this.uses_attr(attr), 'var _WS_'+varForAttr(attr)+' = " "+'+varForAttr(attr)+'+" ";']);
|
||||
},
|
||||
|
||||
save: function(lbl) {
|
||||
@ -470,7 +487,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
var pseudoclschecks = {
|
||||
'first-child': join([
|
||||
'var cel = el;',
|
||||
'while(cel = cel.previousSibling){ if (cel.nodeType === 1) BAD; }',
|
||||
'while(cel = cel.previousSibling){ if (cel.nodeType === 1) BAD; }'
|
||||
]),
|
||||
'last-child': join([
|
||||
'var cel = el;',
|
||||
@ -481,7 +498,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
'var i = 1, cel = el;',
|
||||
'while(cel = cel.previousSibling){',
|
||||
'if (cel.nodeType === 1) i++;',
|
||||
'}',
|
||||
'}'
|
||||
]);
|
||||
|
||||
if (a == 0) return join([
|
||||
@ -530,15 +547,15 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
|
||||
/* Check against class names */
|
||||
$.each(this.classes, function(i, cls){
|
||||
js[js.length] = 'if (__class.indexOf(" '+cls+' ") == -1) BAD;';
|
||||
})
|
||||
js[js.length] = 'if (_WS__class.indexOf(" '+cls+' ") == -1) BAD;';
|
||||
});
|
||||
}
|
||||
|
||||
/* Check against attributes */
|
||||
$.each(this.attrs, function(i, attr){
|
||||
js[js.length] = (attr[1] == '~=') ? el.uses_wsattr(attr[0]) : el.uses_attr(attr[0]);
|
||||
var check = attrchecks[ attr[1] || '-' ];
|
||||
check = check.replace( /K/g, attr[0]).replace( /V/g, attr[2] && attr[2].match(STARTS_WITH_QUOTES) ? attr[2].slice(1,-1) : attr[2] );
|
||||
check = check.replace( /K/g, varForAttr(attr[0])).replace( /V/g, attr[2] && attr[2].match(STARTS_WITH_QUOTES) ? attr[2].slice(1,-1) : attr[2] );
|
||||
js[js.length] = 'if ('+check+') BAD;';
|
||||
});
|
||||
|
||||
@ -555,7 +572,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
el.save(lbl),
|
||||
func,
|
||||
el.restore(lbl)
|
||||
])
|
||||
]);
|
||||
|
||||
js[js.length] = func;
|
||||
});
|
||||
@ -571,7 +588,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
js[js.length] = funcToString(check).replace(/elem/g,'el').replace(/return([^;]+);/,'if (!($1)) BAD;');
|
||||
}
|
||||
else {
|
||||
js[js.length] = 'if (!$.find.selectors.filters.'+pscls[0]+'(el)) BAD;'
|
||||
js[js.length] = 'if (!$.find.selectors.filters.'+pscls[0]+'(el)) BAD;';
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -589,7 +606,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
return join([
|
||||
'l'+(++lbl_id)+':{',
|
||||
f.replace(GOOD, 'break l'+lbl_id),
|
||||
'}',
|
||||
'}'
|
||||
]);
|
||||
else
|
||||
return f.replace(GOOD, '');
|
||||
@ -637,11 +654,11 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
};
|
||||
|
||||
$.selector.Selector.addMethod('compile', function(el) {
|
||||
l = this.parts.length;
|
||||
var l = this.parts.length;
|
||||
|
||||
expr = this.parts[--l].compile(el);
|
||||
var expr = this.parts[--l].compile(el);
|
||||
while (l) {
|
||||
combinator = this.parts[--l];
|
||||
var combinator = this.parts[--l];
|
||||
expr = combines[combinator](el, this.parts[--l], as_subexpr(expr));
|
||||
}
|
||||
|
||||
@ -730,7 +747,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
})(jQuery);;
|
||||
|
||||
|
||||
/* src/jquery.concrete.js */
|
||||
/* src/jquery.entwine.js */
|
||||
|
||||
var console;
|
||||
|
||||
@ -738,28 +755,30 @@ var console;
|
||||
|
||||
var namespaces = {};
|
||||
|
||||
$.concrete = function() {
|
||||
$.fn.concrete.apply(null, arguments);
|
||||
}
|
||||
$.entwine = function() {
|
||||
$.fn.entwine.apply(null, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* A couple of utility functions for accessing the store outside of this closure, and for making things
|
||||
* operate in a little more easy-to-test manner
|
||||
*/
|
||||
$.extend($.concrete, {
|
||||
$.extend($.entwine, {
|
||||
/**
|
||||
* Get all the namespaces. Useful for introspection? Internal interface of Namespace not guaranteed consistant
|
||||
*/
|
||||
namespaces: namespaces,
|
||||
|
||||
/**
|
||||
* Remove all concrete rules
|
||||
* Remove all entwine rules
|
||||
*/
|
||||
clear_all_rules: function() {
|
||||
// Remove proxy functions
|
||||
for (var k in $.fn) { if ($.fn[k].concrete) delete $.fn[k] ; }
|
||||
for (var k in $.fn) { if ($.fn[k].entwine) delete $.fn[k] ; }
|
||||
// Remove bound events - TODO: Make this pluggable, so this code can be moved to jquery.entwine.events.js
|
||||
$(document).unbind('.entwine');
|
||||
// Remove namespaces, and start over again
|
||||
namespaces = $.concrete.namespaces = {};
|
||||
namespaces = $.entwine.namespaces = {};
|
||||
},
|
||||
|
||||
WARN_LEVEL_NONE: 0,
|
||||
@ -773,10 +792,21 @@ var console;
|
||||
|
||||
/** Utility to optionally display warning messages depending on level */
|
||||
warn: function(message, level) {
|
||||
if (level <= $.concrete.warningLevel && console && console.log) {
|
||||
if (level <= $.entwine.warningLevel && console && console.warn) {
|
||||
console.warn(message);
|
||||
if (console.trace) console.trace();
|
||||
}
|
||||
},
|
||||
|
||||
warn_exception: function(where, /* optional: */ on, e) {
|
||||
if ($.entwine.WARN_LEVEL_IMPORTANT <= $.entwine.warningLevel && console && console.warn) {
|
||||
if (arguments.length == 2) { e = on; on = null; }
|
||||
|
||||
if (on) console.warn('Uncaught exception',e,'in',where,'on',on);
|
||||
else console.warn('Uncaught exception',e,'in',where);
|
||||
|
||||
if (e.stack) console.warn("Stack Trace:\n" + e.stack);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -802,9 +832,9 @@ var console;
|
||||
(as[1] - bs[1]) ||
|
||||
(as[2] - bs[2]) ||
|
||||
(a.rulecount - b.rulecount) ;
|
||||
}
|
||||
};
|
||||
|
||||
$.concrete.RuleList = function() {
|
||||
$.entwine.RuleList = function() {
|
||||
var list = [];
|
||||
|
||||
list.addRule = function(selector, name){
|
||||
@ -817,16 +847,16 @@ var console;
|
||||
};
|
||||
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
var handlers = [];
|
||||
|
||||
/**
|
||||
* A Namespace holds all the information needed for adding concrete methods to a namespace (including the _null_ namespace)
|
||||
* A Namespace holds all the information needed for adding entwine methods to a namespace (including the _null_ namespace)
|
||||
*/
|
||||
$.concrete.Namespace = Base.extend({
|
||||
$.entwine.Namespace = Base.extend({
|
||||
init: function(name){
|
||||
if (name && !name.match(/^[A-Za-z0-9.]+$/)) $.concrete.warn('Concrete namespace '+name+' is not formatted as period seperated identifiers', $.concrete.WARN_LEVEL_BESTPRACTISE);
|
||||
if (name && !name.match(/^[A-Za-z0-9.]+$/)) $.entwine.warn('Entwine namespace '+name+' is not formatted as period seperated identifiers', $.entwine.WARN_LEVEL_BESTPRACTISE);
|
||||
name = name || '__base';
|
||||
|
||||
this.name = name;
|
||||
@ -835,12 +865,12 @@ var console;
|
||||
namespaces[name] = this;
|
||||
|
||||
if (name == "__base") {
|
||||
this.injectee = $.fn
|
||||
this.injectee = $.fn;
|
||||
this.$ = $;
|
||||
}
|
||||
else {
|
||||
// We're in a namespace, so we build a Class that subclasses the jQuery Object Class to inject namespace functions into
|
||||
var subfn = function(){}
|
||||
var subfn = function(){};
|
||||
this.injectee = subfn.prototype = new $();
|
||||
|
||||
// And then we provide an overriding $ that returns objects of our new Class, and an overriding pushStack to catch further selection building
|
||||
@ -854,7 +884,7 @@ var console;
|
||||
rv.selector = jq.selector; rv.context = jq.context; var i = rv.length = jq.length;
|
||||
while (i--) rv[i] = jq[i];
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
this.injectee.pushStack = function(elems, name, selector){
|
||||
var ret = bound$(elems);
|
||||
|
||||
@ -867,25 +897,25 @@ var console;
|
||||
|
||||
// Return the newly-formed element set
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// Copy static functions through from $ to this.$ so e.g. $.ajax still works
|
||||
// @bug, @cantfix: Any class functions added to $ after this call won't get mirrored through
|
||||
$.extend(this.$, $);
|
||||
|
||||
// We override concrete to inject the name of this namespace when defining blocks inside this namespace
|
||||
var concrete_wrapper = this.injectee.concrete = function(spacename) {
|
||||
// We override entwine to inject the name of this namespace when defining blocks inside this namespace
|
||||
var entwine_wrapper = this.injectee.entwine = function(spacename) {
|
||||
var args = arguments;
|
||||
|
||||
if (!spacename || typeof spacename != 'string') { args = $.makeArray(args); args.unshift(name); }
|
||||
else if (spacename.charAt(0) != '.') args[0] = name+'.'+spacename;
|
||||
|
||||
return $.fn.concrete.apply(this, args);
|
||||
}
|
||||
return $.fn.entwine.apply(this, args);
|
||||
};
|
||||
|
||||
this.$.concrete = function() {
|
||||
concrete_wrapper.apply(null, arguments);
|
||||
}
|
||||
this.$.entwine = function() {
|
||||
entwine_wrapper.apply(null, arguments);
|
||||
};
|
||||
|
||||
for (var i = 0; i < handlers.length; i++) {
|
||||
var handler = handlers[i], builder;
|
||||
@ -896,10 +926,10 @@ var console;
|
||||
for (var k in overrides) this.injectee[k] = overrides[k];
|
||||
}
|
||||
|
||||
// Inject $.concrete function overrides
|
||||
// Inject $.entwine function overrides
|
||||
if (builder = handler.namespaceStaticOverrides) {
|
||||
var overrides = builder(this);
|
||||
for (var k in overrides) this.$.concrete[k] = overrides[k];
|
||||
for (var k in overrides) this.$.entwine[k] = overrides[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -910,8 +940,9 @@ var console;
|
||||
* Used by proxy for all calls, and by ctorProxy to handle _super calls
|
||||
* @param {String} name - name of the function as passed in the construction object
|
||||
* @param {String} funcprop - the property on the Rule object that gives the actual function to call
|
||||
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
|
||||
*/
|
||||
one: function(name, funcprop) {
|
||||
one: function(name, funcprop, basefunc) {
|
||||
var namespace = this;
|
||||
var funcs = this.store[name];
|
||||
|
||||
@ -926,7 +957,9 @@ var console;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we didn't find a entwine-defined function, but there is a non-entwine function to use as a base, try that
|
||||
if (basefunc) return basefunc.apply(namespace.$(el), args);
|
||||
};
|
||||
|
||||
return one;
|
||||
},
|
||||
@ -935,9 +968,10 @@ var console;
|
||||
* A proxy is a function attached to a callable object (either the base jQuery.fn or a subspace object) which handles
|
||||
* finding and calling the correct function for each member of the current jQuery context
|
||||
* @param {String} name - name of the function as passed in the construction object
|
||||
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
|
||||
*/
|
||||
build_proxy: function(name) {
|
||||
var one = this.one(name, 'func');
|
||||
build_proxy: function(name, basefunc) {
|
||||
var one = this.one(name, 'func', basefunc);
|
||||
|
||||
var prxy = function() {
|
||||
var rv, ctx = $(this);
|
||||
@ -951,17 +985,17 @@ var console;
|
||||
},
|
||||
|
||||
bind_proxy: function(selector, name, func) {
|
||||
var rulelist = this.store[name] || (this.store[name] = $.concrete.RuleList());
|
||||
var rulelist = this.store[name] || (this.store[name] = $.entwine.RuleList());
|
||||
|
||||
var rule = rulelist.addRule(selector, name); rule.func = func;
|
||||
|
||||
if (!this.injectee.hasOwnProperty(name)) {
|
||||
this.injectee[name] = this.build_proxy(name);
|
||||
this.injectee[name].concrete = true;
|
||||
if (!this.injectee.hasOwnProperty(name) || !this.injectee[name].entwine) {
|
||||
this.injectee[name] = this.build_proxy(name, this.injectee.hasOwnProperty(name) ? this.injectee[name] : null);
|
||||
this.injectee[name].entwine = true;
|
||||
}
|
||||
|
||||
if (!this.injectee[name].concrete) {
|
||||
$.concrete.warn('Warning: Concrete function '+name+' clashes with regular jQuery function - concrete function will not be callable directly on jQuery object', $.concrete.WARN_LEVEL_IMPORTANT);
|
||||
if (!this.injectee[name].entwine) {
|
||||
$.entwine.warn('Warning: Entwine function '+name+' clashes with regular jQuery function - entwine function will not be callable directly on jQuery object', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
},
|
||||
|
||||
@ -993,12 +1027,12 @@ var console;
|
||||
* A handler is some javascript code that adds support for some time of key / value pair passed in the hash to the Namespace add method.
|
||||
* The default handlers provided (and included by default) are event, ctor and properties
|
||||
*/
|
||||
$.concrete.Namespace.addHandler = function(handler) {
|
||||
$.entwine.Namespace.addHandler = function(handler) {
|
||||
for (var i = 0; i < handlers.length && handlers[i].order < handler.order; i++) { /* Pass */ }
|
||||
handlers.splice(i, 0, handler);
|
||||
}
|
||||
};
|
||||
|
||||
$.concrete.Namespace.addHandler({
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 50,
|
||||
|
||||
bind: function(selector, k, v){
|
||||
@ -1011,20 +1045,22 @@ var console;
|
||||
|
||||
$.extend($.fn, {
|
||||
/**
|
||||
* Main concrete function. Used for new definitions, calling into a namespace (or forcing the base namespace) and entering a using block
|
||||
* Main entwine function. Used for new definitions, calling into a namespace (or forcing the base namespace) and entering a using block
|
||||
*
|
||||
*/
|
||||
concrete: function(spacename) {
|
||||
entwine: function(spacename) {
|
||||
var i = 0;
|
||||
var selector = this.selector ? $.selector(this.selector) : null;
|
||||
/* Don't actually work out selector until we try and define something on it - we might be opening a namespace on an function-traveresed object
|
||||
which have non-standard selectors like .parents(.foo).slice(0,1) */
|
||||
var selector = null;
|
||||
|
||||
/* By default we operator on the base namespace */
|
||||
var namespace = namespaces.__base || $.concrete.Namespace();
|
||||
var namespace = namespaces.__base || $.entwine.Namespace();
|
||||
|
||||
/* If the first argument is a string, then it's the name of a namespace. Look it up */
|
||||
if (typeof spacename == 'string') {
|
||||
if (spacename.charAt('0') == '.') spacename = spacename.substr(1);
|
||||
if (spacename) namespace = namespaces[spacename] || $.concrete.Namespace(spacename);
|
||||
if (spacename) namespace = namespaces[spacename] || $.entwine.Namespace(spacename);
|
||||
i=1;
|
||||
}
|
||||
|
||||
@ -1032,19 +1068,19 @@ var console;
|
||||
while (i < arguments.length) {
|
||||
var res = arguments[i++];
|
||||
|
||||
// If it's a function, call it - either it's a using block or it's a namespaced concrete definition
|
||||
// If it's a function, call it - either it's a using block or it's a namespaced entwine definition
|
||||
if ($.isFunction(res)) {
|
||||
if (res.length != 1) $.concrete.warn('Function block inside concrete definition does not take $ argument properly', $.concrete.WARN_LEVEL_IMPORTANT);
|
||||
if (res.length != 1) $.entwine.warn('Function block inside entwine definition does not take $ argument properly', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
res = res.call(namespace.$(this), namespace.$);
|
||||
}
|
||||
|
||||
// If we have a concrete definition hash, inject it into namespace
|
||||
// If we have a entwine definition hash, inject it into namespace
|
||||
if (res) {
|
||||
if (selector === null) selector = this.selector ? $.selector(this.selector) : false;
|
||||
|
||||
if (selector) namespace.add(selector, res);
|
||||
else $.concrete.warn('Concrete block given to concrete call without selector. Make sure you call $(selector).concrete when defining blocks', $.concrete.WARN_LEVEL_IMPORTANT);
|
||||
else $.entwine.warn('Entwine block given to entwine call without selector. Make sure you call $(selector).entwine when defining blocks', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Finally, return the jQuery object 'this' refers to, wrapped in the new namespace */
|
||||
@ -1052,7 +1088,7 @@ var console;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls the next most specific version of the current concrete method
|
||||
* Calls the next most specific version of the current entwine method
|
||||
*/
|
||||
_super: function(){
|
||||
var rv, i = this.length;
|
||||
@ -1068,7 +1104,7 @@ var console;
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.concrete.dommaybechanged.js */
|
||||
/* src/jquery.entwine.dommaybechanged.js */
|
||||
|
||||
(function($){
|
||||
|
||||
@ -1082,9 +1118,9 @@ var console;
|
||||
var triggerEvent = function() {
|
||||
$(document).triggerHandler('DOMMaybeChanged');
|
||||
check_id = null;
|
||||
}
|
||||
};
|
||||
|
||||
$.extend($.concrete, {
|
||||
$.extend($.entwine, {
|
||||
/**
|
||||
* Make onmatch and onunmatch work in synchronous mode - that is, new elements will be detected immediately after
|
||||
* the DOM manipulation that made them match. This is only really useful for during testing, since it's pretty slow
|
||||
@ -1092,7 +1128,7 @@ var console;
|
||||
*/
|
||||
synchronous_mode: function() {
|
||||
if (check_id) clearTimeout(check_id); check_id = null;
|
||||
runSoon = function(func, delay){ func.call(this); return null; }
|
||||
runSoon = function(func, delay){ func.call(this); return null; };
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1111,8 +1147,8 @@ var console;
|
||||
var rv = old.apply(this, arguments);
|
||||
if (!check_id) check_id = runSoon(triggerEvent, 100);
|
||||
return rv;
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function registerSetterGetterFunction() {
|
||||
@ -1122,8 +1158,8 @@ var console;
|
||||
var rv = old.apply(this, arguments);
|
||||
if (!check_id && (b !== undefined || typeof a != 'string')) check_id = runSoon(triggerEvent, 100);
|
||||
return rv;
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Register core DOM manipulation methods
|
||||
@ -1131,12 +1167,12 @@ var console;
|
||||
registerSetterGetterFunction('attr');
|
||||
|
||||
// And on DOM ready, trigger matching once
|
||||
$(function(){ triggerEvent(); })
|
||||
$(function(){ triggerEvent(); });
|
||||
|
||||
})(jQuery);;
|
||||
|
||||
|
||||
/* src/jquery.concrete.events.js */
|
||||
/* src/jquery.entwine.events.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
@ -1148,24 +1184,26 @@ var console;
|
||||
if (document.compareDocumentPosition) {
|
||||
var is_or_contains = function(a, b) {
|
||||
return a && b && (a == b || !!(a.compareDocumentPosition(b) & 16));
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
var is_or_contains = function(a, b) {
|
||||
return a && b && (a == b || (a.contains ? a.contains(b) : true));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Add the methods to handle event binding to the Namespace class */
|
||||
$.concrete.Namespace.addMethods({
|
||||
$.entwine.Namespace.addMethods({
|
||||
build_event_proxy: function(name) {
|
||||
var one = this.one(name, 'func');
|
||||
|
||||
var prxy = function(e, originalevent) {
|
||||
e = originalevent || e;
|
||||
var prxy = function(e, data) {
|
||||
// For events that do not bubble we manually trigger delegation (see delegate_submit below)
|
||||
// If this event is a manual trigger, the event we actually want to bubble is attached as a property of the passed event
|
||||
e = e.delegatedEvent || e;
|
||||
|
||||
var el = e.target;
|
||||
while (el && el != document && !e.isPropagationStopped()) {
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
var ret = one(el, arguments);
|
||||
if (ret !== undefined) e.result = ret;
|
||||
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
||||
@ -1184,7 +1222,7 @@ var console;
|
||||
var el = e.target;
|
||||
var rel = e.relatedTarget;
|
||||
|
||||
while (el && el != document && !e.isPropagationStopped()) {
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
/* We know el contained target. If it also contains relatedTarget then we didn't mouseenter / leave. What's more, every ancestor will also
|
||||
contan el and rel, and so we can just stop bubbling */
|
||||
if (is_or_contains(el, rel)) break;
|
||||
@ -1232,7 +1270,7 @@ var console;
|
||||
|
||||
// And if we decided that a change happened, do the actual triggering
|
||||
if (e.type == 'change') {
|
||||
while (el && el != document && !e.isPropagationStopped()) {
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
var ret = one(el, arguments);
|
||||
if (ret !== undefined) e.result = ret;
|
||||
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
||||
@ -1246,7 +1284,7 @@ var console;
|
||||
},
|
||||
|
||||
bind_event: function(selector, name, func, event) {
|
||||
var funcs = this.store[name] || (this.store[name] = $.concrete.RuleList()) ;
|
||||
var funcs = this.store[name] || (this.store[name] = $.entwine.RuleList()) ;
|
||||
var proxies = funcs.proxies || (funcs.proxies = {});
|
||||
|
||||
var rule = funcs.addRule(selector, name); rule.func = func;
|
||||
@ -1268,19 +1306,22 @@ var console;
|
||||
}
|
||||
break;
|
||||
case 'onsubmit':
|
||||
event = 'delegated_submit';
|
||||
event = 'delegatedSubmit';
|
||||
break;
|
||||
case 'onfocus':
|
||||
case 'onblur':
|
||||
$.concrete.warn('Event '+event+' not supported - using focusin / focusout instead', $.concrete.WARN_LEVEL_IMPORTANT);
|
||||
$.entwine.warn('Event '+event+' not supported - using focusin / focusout instead', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
|
||||
// If none of the special handlers created a proxy, use the generic proxy
|
||||
if (!proxies[name]) proxies[name] = this.build_event_proxy(name);
|
||||
$(document).bind(event, proxies[name]);
|
||||
|
||||
$(document).bind(event+'.entwine', proxies[name]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.concrete.Namespace.addHandler({
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 40,
|
||||
|
||||
bind: function(selector, k, v){
|
||||
@ -1293,10 +1334,14 @@ var console;
|
||||
}
|
||||
});
|
||||
|
||||
// Find all forms and bind onsubmit to trigger on the document too. This is the only event that can't be grabbed via delegation.
|
||||
// Find all forms and bind onsubmit to trigger on the document too.
|
||||
// This is the only event that can't be grabbed via delegation
|
||||
|
||||
var form_binding_cache = $([]); // A cache for already-handled form elements
|
||||
var delegate_submit = function(e){ $(document).triggerHandler('delegated_submit', e); } // The function that handles the delegation
|
||||
var delegate_submit = function(e, data){
|
||||
var delegationEvent = $.Event('delegatedSubmit'); delegationEvent.delegatedEvent = e;
|
||||
return $(document).trigger(delegationEvent, data);
|
||||
};
|
||||
|
||||
$(document).bind('DOMMaybeChanged', function(){
|
||||
var forms = $('form');
|
||||
@ -1310,14 +1355,14 @@ var console;
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.concrete.ctors.js */
|
||||
/* src/jquery.entwine.ctors.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
/* Add the methods to handle constructor & destructor binding to the Namespace class */
|
||||
$.concrete.Namespace.addMethods({
|
||||
$.entwine.Namespace.addMethods({
|
||||
bind_condesc: function(selector, name, func) {
|
||||
var ctors = this.store.ctors || (this.store.ctors = $.concrete.RuleList()) ;
|
||||
var ctors = this.store.ctors || (this.store.ctors = $.entwine.RuleList()) ;
|
||||
|
||||
var rule;
|
||||
for (var i = 0 ; i < ctors.length; i++) {
|
||||
@ -1342,17 +1387,19 @@ var console;
|
||||
|
||||
var tmp_i = el.i, tmp_f = el.f;
|
||||
el.i = i; el.f = one;
|
||||
try { func.call(namespace.$(el)); }
|
||||
catch(e) { el.i = tmp_i; el.f = tmp_f; }
|
||||
|
||||
try { func.call(namespace.$(el)); }
|
||||
catch(e) { $.entwine.warn_exception(name, el, e); }
|
||||
finally { el.i = tmp_i; el.f = tmp_f; }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ctors[name+'proxy'] = proxy;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.concrete.Namespace.addHandler({
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 30,
|
||||
|
||||
bind: function(selector, k, v) {
|
||||
@ -1375,29 +1422,35 @@ var console;
|
||||
*/
|
||||
$(document).bind('DOMMaybeChanged', function(){
|
||||
// For every namespace
|
||||
for (var k in $.concrete.namespaces) {
|
||||
for (var k in $.entwine.namespaces) {
|
||||
// That has constructors or destructors
|
||||
var ctors = $.concrete.namespaces[k].store.ctors;
|
||||
var ctors = $.entwine.namespaces[k].store.ctors;
|
||||
if (ctors) {
|
||||
|
||||
// Keep a record of elements that have matched already
|
||||
var matched = $([]), match, add, rem;
|
||||
var matched = $([]), add, rem, res, rule, sel, ctor, dtor;
|
||||
// Stepping through each selector from most to least specific
|
||||
var j = ctors.length;
|
||||
while (j--) {
|
||||
// Build some quick-acccess variables
|
||||
var sel = ctors[j].selector.selector, ctor = ctors[j].onmatch; dtor = ctors[j].onunmatch;
|
||||
// Build some quick-access variables
|
||||
rule = ctors[j];
|
||||
sel = rule.selector.selector;
|
||||
ctor = rule.onmatch;
|
||||
dtor = rule.onunmatch;
|
||||
|
||||
// Get the list of elements that match this selector, that haven't yet matched a more specific selector
|
||||
res = add = $(sel).not(matched);
|
||||
|
||||
// If this selector has a list of elements it matched against last time
|
||||
if (ctors[j].cache) {
|
||||
// If this selector has a list of elements it matched against last time
|
||||
if (rule.cache) {
|
||||
// Find the ones that are extra this time
|
||||
add = res.not(ctors[j].cache);
|
||||
// Find the ones that are gone this time
|
||||
rem = ctors[j].cache.not(res);
|
||||
// And call the desctructor on them
|
||||
if (rem.length && dtor) ctors.onunmatchproxy(rem, j, dtor);
|
||||
add = res.not(rule.cache);
|
||||
if (dtor) {
|
||||
// Find the ones that are gone this time
|
||||
rem = rule.cache.not(res);
|
||||
// And call the destructor on them
|
||||
if (rem.length) ctors.onunmatchproxy(rem, j, dtor);
|
||||
}
|
||||
}
|
||||
|
||||
// Call the constructor on the newly matched ones
|
||||
@ -1410,32 +1463,32 @@ var console;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.concrete.properties.js */
|
||||
/* src/jquery.entwine.properties.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
var concrete_prepend = '__concrete!';
|
||||
var entwine_prepend = '__entwine!';
|
||||
|
||||
var getConcreteData = function(el, namespace, property) {
|
||||
return el.data(concrete_prepend + namespace + '!' + property);
|
||||
}
|
||||
var getEntwineData = function(el, namespace, property) {
|
||||
return el.data(entwine_prepend + namespace + '!' + property);
|
||||
};
|
||||
|
||||
var setConcreteData = function(el, namespace, property, value) {
|
||||
return el.data(concrete_prepend + namespace + '!' + property, value);
|
||||
}
|
||||
var setEntwineData = function(el, namespace, property, value) {
|
||||
return el.data(entwine_prepend + namespace + '!' + property, value);
|
||||
};
|
||||
|
||||
var getConcreteDataAsHash = function(el, namespace) {
|
||||
var getEntwineDataAsHash = function(el, namespace) {
|
||||
var hash = {};
|
||||
var id = jQuery.data(el[0]);
|
||||
|
||||
var matchstr = concrete_prepend + namespace + '!';
|
||||
var matchstr = entwine_prepend + namespace + '!';
|
||||
var matchlen = matchstr.length;
|
||||
|
||||
var cache = jQuery.cache[id];
|
||||
@ -1444,52 +1497,60 @@ var console;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
var setConcreteDataFromHash = function(el, namespace, hash) {
|
||||
for (var k in hash) setConcreteData(namespace, k, hash[k]);
|
||||
}
|
||||
var setEntwineDataFromHash = function(el, namespace, hash) {
|
||||
for (var k in hash) setEntwineData(namespace, k, hash[k]);
|
||||
};
|
||||
|
||||
var concreteData = function(el, namespace, args) {
|
||||
var entwineData = function(el, namespace, args) {
|
||||
switch (args.length) {
|
||||
case 0:
|
||||
return getConcreteDataAsHash(el, namespace);
|
||||
return getEntwineDataAsHash(el, namespace);
|
||||
case 1:
|
||||
if (typeof args[0] == 'string') return getConcreteData(el, namespace, args[0]);
|
||||
else return setConcreteDataFromHash(el, namespace, args[0]);
|
||||
if (typeof args[0] == 'string') return getEntwineData(el, namespace, args[0]);
|
||||
else return setEntwineDataFromHash(el, namespace, args[0]);
|
||||
default:
|
||||
return setConcreteData(el, namespace, args[0], args[1]);
|
||||
return setEntwineData(el, namespace, args[0], args[1]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.extend($.fn, {
|
||||
concreteData: function() {
|
||||
return concreteData(this, '__base', arguments);
|
||||
entwineData: function() {
|
||||
return entwineData(this, '__base', arguments);
|
||||
}
|
||||
});
|
||||
|
||||
$.concrete.Namespace.addHandler({
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 60,
|
||||
|
||||
bind: function(selector, k, v) {
|
||||
if (k.charAt(0) != k.charAt(0).toUpperCase()) $.concrete.warn('Concrete property '+k+' does not start with a capital letter', $.concrete.WARN_LEVEL_BESTPRACTISE);
|
||||
if (k.charAt(0) != k.charAt(0).toUpperCase()) $.entwine.warn('Entwine property '+k+' does not start with a capital letter', $.entwine.WARN_LEVEL_BESTPRACTISE);
|
||||
|
||||
var namespace = this;
|
||||
g = function() { return this.concreteData(k) || v ; }
|
||||
s = function(v){ return this.concreteData(k, v); }
|
||||
// Create the getters and setters
|
||||
|
||||
g.pname = s.pname = k;
|
||||
var getterName = 'get'+k;
|
||||
var setterName = 'set'+k;
|
||||
|
||||
this.bind_proxy(selector, 'get'+k, g);
|
||||
this.bind_proxy(selector, 'set'+k, s);
|
||||
this.bind_proxy(selector, getterName, function() { return this.entwineData(k) || v ; });
|
||||
this.bind_proxy(selector, setterName, function(v){ return this.entwineData(k, v); });
|
||||
|
||||
// Get the get and set proxies we just created
|
||||
|
||||
var getter = this.injectee[getterName];
|
||||
var setter = this.injectee[setterName];
|
||||
|
||||
// And bind in the jQuery-style accessor
|
||||
|
||||
this.bind_proxy(selector, k, function(v){ return (arguments.length == 1 ? setter : getter).call(this, v) ; });
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
namespaceMethodOverrides: function(namespace){
|
||||
return {
|
||||
concreteData: function() {
|
||||
return concreteData(this, namespace.name, arguments);
|
||||
entwineData: function() {
|
||||
return entwineData(this, namespace.name, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1498,3 +1559,29 @@ var console;
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.entwine.legacy.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
// Adds back concrete methods for backwards compatibility
|
||||
$.concrete = $.entwine;
|
||||
$.fn.concrete = $.fn.entwine;
|
||||
$.fn.concreteData = $.fn.entwineData;
|
||||
|
||||
// Use addHandler to hack in the namespace.$.concrete equivilent to the namespace.$.entwine namespace-injection
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 100,
|
||||
bind: function(selector, k, v) { return false; },
|
||||
|
||||
namespaceMethodOverrides: function(namespace){
|
||||
namespace.$.concrete = namespace.$.entwine;
|
||||
namespace.injectee.concrete = namespace.injectee.entwine;
|
||||
namespace.injectee.concreteData = namespace.injectee.entwineData;
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
1587
thirdparty/jquery-entwine/dist/jquery.entwine-dist.js
vendored
Normal file
@ -0,0 +1,1587 @@
|
||||
/* jQuery.Entwine - Copyright 2009 Hamish Friedlander and SilverStripe. Version . */
|
||||
|
||||
/* vendor/jquery.selector/jquery.class.js */
|
||||
|
||||
/**
|
||||
* Very basic Class utility. Based on base and jquery.class.
|
||||
*
|
||||
* Class definition: var Foo = Base.extend({ init: function(){ Constructor }; method_name: function(){ Method } });
|
||||
*
|
||||
* Inheritance: var Bar = Foo.extend({ method_name: function(){ this._super(); } });
|
||||
*
|
||||
* new-less Constructor: new Foo(arg) <-same as-> Foo(arg)
|
||||
*/
|
||||
|
||||
var Base;
|
||||
|
||||
(function(){
|
||||
|
||||
var marker = {}, fnTest = /xyz/.test(function(){var xyz;}) ? /\b_super\b/ : /.*/;
|
||||
|
||||
// The base Class implementation (does nothing)
|
||||
Base = function(){};
|
||||
|
||||
Base.addMethod = function(name, func) {
|
||||
var parent = this._super && this._super.prototype;
|
||||
|
||||
if (parent && fnTest.test(func)) {
|
||||
this.prototype[name] = function(){
|
||||
var tmp = this._super;
|
||||
this._super = parent[name];
|
||||
try {
|
||||
var ret = func.apply(this, arguments);
|
||||
}
|
||||
finally {
|
||||
this._super = tmp;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
else this.prototype[name] = func;
|
||||
};
|
||||
|
||||
Base.addMethods = function(props) {
|
||||
for (var name in props) {
|
||||
if (typeof props[name] == 'function') this.addMethod(name, props[name]);
|
||||
else this.prototype[name] = props[name];
|
||||
}
|
||||
};
|
||||
|
||||
Base.subclassOf = function(parentkls) {
|
||||
var kls = this;
|
||||
while (kls) {
|
||||
if (kls === parentkls) return true;
|
||||
kls = kls._super;
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
Base.extend = function(props) {
|
||||
|
||||
// The dummy class constructor
|
||||
var Kls = function() {
|
||||
if (arguments[0] === marker) return;
|
||||
|
||||
if (this instanceof Kls) {
|
||||
if (this.init) this.init.apply(this, arguments);
|
||||
}
|
||||
else {
|
||||
var ret = new Kls(marker); if (ret.init) ret.init.apply(ret, arguments); return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// Add the common class variables and methods
|
||||
Kls.constructor = Kls;
|
||||
Kls.extend = Base.extend;
|
||||
Kls.addMethod = Base.addMethod;
|
||||
Kls.addMethods = Base.addMethods;
|
||||
Kls.subclassOf = Base.subclassOf;
|
||||
|
||||
Kls._super = this;
|
||||
|
||||
// Attach the parent object to the inheritance chain
|
||||
Kls.prototype = new this(marker);
|
||||
Kls.prototype.constructor = Kls;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
Kls.addMethods(props);
|
||||
|
||||
return Kls;
|
||||
};
|
||||
})();;
|
||||
|
||||
|
||||
/* vendor/jquery.selector/jquery.selector.js */
|
||||
|
||||
(function($){
|
||||
|
||||
var tokens = {
|
||||
UNICODE: /\\[0-9a-f]{1,6}(?:\r\n|[ \n\r\t\f])?/,
|
||||
ESCAPE: /(?:UNICODE)|\\[^\n\r\f0-9a-f]/,
|
||||
NONASCII: /[^\x00-\x7F]/,
|
||||
NMSTART: /[_a-z]|(?:NONASCII)|(?:ESCAPE)/,
|
||||
NMCHAR: /[_a-z0-9-]|(?:NONASCII)|(?:ESCAPE)/,
|
||||
IDENT: /-?(?:NMSTART)(?:NMCHAR)*/,
|
||||
|
||||
NL: /\n|\r\n|\r|\f/,
|
||||
|
||||
STRING: /(?:STRING1)|(?:STRING2)|(?:STRINGBARE)/,
|
||||
STRING1: /"(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\"])*"/,
|
||||
STRING2: /'(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\'])*'/,
|
||||
STRINGBARE: /(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\]])*/,
|
||||
|
||||
FUNCTION: /(?:IDENT)\(\)/,
|
||||
|
||||
INTEGER: /[0-9]+/,
|
||||
|
||||
WITHN: /([-+])?(INTEGER)?(n)\s*(?:([-+])\s*(INTEGER))?/,
|
||||
WITHOUTN: /([-+])?(INTEGER)/
|
||||
};
|
||||
|
||||
var rx = {
|
||||
not: /:not\(/,
|
||||
not_end: /\)/,
|
||||
|
||||
tag: /((?:IDENT)|\*)/,
|
||||
id: /#(IDENT)/,
|
||||
cls: /\.(IDENT)/,
|
||||
attr: /\[\s*(IDENT)\s*(?:([^=]?=)\s*(STRING)\s*)?\]/,
|
||||
pseudo_el: /(?::(first-line|first-letter|before|after))|(?:::((?:FUNCTION)|(?:IDENT)))/,
|
||||
pseudo_cls_nth: /:nth-child\(\s*(?:(?:WITHN)|(?:WITHOUTN)|(odd|even))\s*\)/,
|
||||
pseudo_cls: /:(IDENT)/,
|
||||
|
||||
comb: /\s*(\+|~|>)\s*|\s+/,
|
||||
comma: /\s*,\s*/,
|
||||
important: /\s+!important\s*$/
|
||||
};
|
||||
|
||||
/* Replace placeholders with actual regex, and mark all as case insensitive */
|
||||
var token = /[A-Z][A-Z0-9]+/;
|
||||
for (var k in rx) {
|
||||
var m, src = rx[k].source;
|
||||
while (m = src.match(token)) src = src.replace(m[0], tokens[m[0]].source);
|
||||
rx[k] = new RegExp(src, 'gi');
|
||||
}
|
||||
|
||||
/**
|
||||
* A string that matches itself against regexii, and keeps track of how much of itself has been matched
|
||||
*/
|
||||
var ConsumableString = Base.extend({
|
||||
init: function(str) {
|
||||
this.str = str;
|
||||
this.pos = 0;
|
||||
},
|
||||
match: function(rx) {
|
||||
var m;
|
||||
rx.lastIndex = this.pos;
|
||||
if ((m = rx.exec(this.str)) && m.index == this.pos ) {
|
||||
this.pos = rx.lastIndex ? rx.lastIndex : this.str.length ;
|
||||
return m;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
peek: function(rx) {
|
||||
var m;
|
||||
rx.lastIndex = this.pos;
|
||||
if ((m = rx.exec(this.str)) && m.index == this.pos ) return m;
|
||||
return null;
|
||||
},
|
||||
showpos: function() {
|
||||
return this.str.slice(0,this.pos)+'<HERE>' + this.str.slice(this.pos);
|
||||
},
|
||||
done: function() {
|
||||
return this.pos == this.str.length;
|
||||
}
|
||||
});
|
||||
|
||||
/* A base class that all Selectors inherit off */
|
||||
var SelectorBase = Base.extend({});
|
||||
|
||||
/**
|
||||
* A class representing a Simple Selector, as per the CSS3 selector spec
|
||||
*/
|
||||
var SimpleSelector = SelectorBase.extend({
|
||||
init: function() {
|
||||
this.tag = null;
|
||||
this.id = null;
|
||||
this.classes = [];
|
||||
this.attrs = [];
|
||||
this.nots = [];
|
||||
this.pseudo_classes = [];
|
||||
this.pseudo_els = [];
|
||||
},
|
||||
parse: function(selector) {
|
||||
var m;
|
||||
|
||||
/* Pull out the initial tag first, if there is one */
|
||||
if (m = selector.match(rx.tag)) this.tag = m[1];
|
||||
|
||||
/* Then for each selection type, try and find a match */
|
||||
do {
|
||||
if (m = selector.match(rx.not)) {
|
||||
this.nots[this.nots.length] = SelectorsGroup().parse(selector);
|
||||
if (!(m = selector.match(rx.not_end))) {
|
||||
throw 'Invalid :not term in selector';
|
||||
}
|
||||
}
|
||||
else if (m = selector.match(rx.id)) this.id = m[1];
|
||||
else if (m = selector.match(rx.cls)) this.classes[this.classes.length] = m[1];
|
||||
else if (m = selector.match(rx.attr)) this.attrs[this.attrs.length] = [ m[1], m[2], m[3] ];
|
||||
else if (m = selector.match(rx.pseudo_el)) this.pseudo_els[this.pseudo_els.length] = m[1] || m[2];
|
||||
else if (m = selector.match(rx.pseudo_cls_nth)) {
|
||||
if (m[3]) {
|
||||
var a = parseInt((m[1]||'')+(m[2]||'1'));
|
||||
var b = parseInt((m[4]||'')+(m[5]||'0'));
|
||||
}
|
||||
else {
|
||||
var a = m[8] ? 2 : 0;
|
||||
var b = m[8] ? (4-m[8].length) : parseInt((m[6]||'')+m[7]);
|
||||
}
|
||||
this.pseudo_classes[this.pseudo_classes.length] = ['nth-child', [a, b]];
|
||||
}
|
||||
else if (m = selector.match(rx.pseudo_cls)) this.pseudo_classes[this.pseudo_classes.length] = [m[1]];
|
||||
|
||||
} while(m && !selector.done());
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A class representing a Selector, as per the CSS3 selector spec
|
||||
*/
|
||||
var Selector = SelectorBase.extend({
|
||||
init: function(){
|
||||
this.parts = [];
|
||||
},
|
||||
parse: function(cons){
|
||||
this.parts[this.parts.length] = SimpleSelector().parse(cons);
|
||||
|
||||
while (!cons.done() && !cons.peek(rx.comma) && (m = cons.match(rx.comb))) {
|
||||
this.parts[this.parts.length] = m[1] || ' ';
|
||||
this.parts[this.parts.length] = SimpleSelector().parse(cons);
|
||||
}
|
||||
|
||||
return this.parts.length == 1 ? this.parts[0] : this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A class representing a sequence of selectors, as per the CSS3 selector spec
|
||||
*/
|
||||
var SelectorsGroup = SelectorBase.extend({
|
||||
init: function(){
|
||||
this.parts = [];
|
||||
},
|
||||
parse: function(cons){
|
||||
this.parts[this.parts.length] = Selector().parse(cons);
|
||||
|
||||
while (!cons.done() && (m = cons.match(rx.comma))) {
|
||||
this.parts[this.parts.length] = Selector().parse(cons);
|
||||
}
|
||||
|
||||
return this.parts.length == 1 ? this.parts[0] : this;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$.selector = function(s){
|
||||
var cons = ConsumableString(s);
|
||||
var res = SelectorsGroup().parse(cons);
|
||||
|
||||
res.selector = s;
|
||||
|
||||
if (!cons.done()) throw 'Could not parse selector - ' + cons.showpos() ;
|
||||
else return res;
|
||||
};
|
||||
|
||||
$.selector.SelectorBase = SelectorBase;
|
||||
$.selector.SimpleSelector = SimpleSelector;
|
||||
$.selector.Selector = Selector;
|
||||
$.selector.SelectorsGroup = SelectorsGroup;
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
/* vendor/jquery.selector/jquery.selector.specifity.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
$.selector.SimpleSelector.addMethod('specifity', function() {
|
||||
if (this.spec) return this.spec;
|
||||
|
||||
var spec = [
|
||||
this.id ? 1 : 0,
|
||||
this.classes.length + this.attrs.length + this.pseudo_classes.length,
|
||||
((this.tag && this.tag != '*') ? 1 : 0) + this.pseudo_els.length
|
||||
];
|
||||
$.each(this.nots, function(i,not){
|
||||
var ns = not.specifity(); spec[0] += ns[0]; spec[1] += ns[1]; spec[2] += ns[2];
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
});
|
||||
|
||||
$.selector.Selector.addMethod('specifity', function(){
|
||||
if (this.spec) return this.spec;
|
||||
|
||||
var spec = [0,0,0];
|
||||
$.each(this.parts, function(i,part){
|
||||
if (i%2) return;
|
||||
var ps = part.specifity(); spec[0] += ps[0]; spec[1] += ps[1]; spec[2] += ps[2];
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
});
|
||||
|
||||
$.selector.SelectorsGroup.addMethod('specifity', function(){
|
||||
if (this.spec) return this.spec;
|
||||
|
||||
var spec = [0,0,0];
|
||||
$.each(this.parts, function(i,part){
|
||||
var ps = part.specifity(); spec[0] += ps[0]; spec[1] += ps[1]; spec[2] += ps[2];
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
/* vendor/jquery.selector/jquery.selector.matches.js */
|
||||
|
||||
/*
|
||||
This attempts to do the opposite of Sizzle.
|
||||
Sizzle is good for finding elements for a selector, but not so good for telling if an individual element matches a selector
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
/**** CAPABILITY TESTS ****/
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = '<form id="test"><input name="id" type="text"/></form>';
|
||||
|
||||
// In IE 6-7, getAttribute often does the wrong thing (returns similar to el.attr), so we need to use getAttributeNode on that browser
|
||||
var getAttributeDodgy = div.firstChild.getAttribute('id') !== 'test';
|
||||
|
||||
// Does browser support Element.firstElementChild, Element.previousElementSibling, etc.
|
||||
var hasElementTraversal = div.firstElementChild && div.firstElementChild.tagName == 'FORM';
|
||||
|
||||
// Does browser support Element.children
|
||||
var hasChildren = div.children && div.children[0].tagName == 'FORM';
|
||||
|
||||
var FUNC_IN = /^\s*function\s*\([^)]*\)\s*\{/;
|
||||
var FUNC_OUT = /}\s*$/;
|
||||
|
||||
var funcToString = function(f) {
|
||||
return (''+f).replace(FUNC_IN,'').replace(FUNC_OUT,'');
|
||||
};
|
||||
|
||||
// Can we use Function#toString ?
|
||||
try {
|
||||
var testFunc = function(){ return 'good'; };
|
||||
if ((new Function('',funcToString(testFunc)))() != 'good') funcToString = false;
|
||||
}
|
||||
catch(e) { funcToString = false; console.log(e.message);/*pass*/ }
|
||||
|
||||
/**** INTRO ****/
|
||||
|
||||
var GOOD = /GOOD/g;
|
||||
var BAD = /BAD/g;
|
||||
|
||||
var STARTS_WITH_QUOTES = /^['"]/g;
|
||||
|
||||
var join = function(js) {
|
||||
return js.join('\n');
|
||||
};
|
||||
|
||||
var join_complex = function(js) {
|
||||
var code = new String(js.join('\n')); // String objects can have properties set. strings can't
|
||||
code.complex = true;
|
||||
return code;
|
||||
};
|
||||
|
||||
/**** ATTRIBUTE ACCESSORS ****/
|
||||
|
||||
// Not all attribute names can be used as identifiers, so we encode any non-acceptable characters as hex
|
||||
var varForAttr = function(attr) {
|
||||
return '_' + attr.replace(/^[^A-Za-z]|[^A-Za-z0-9]/g, function(m){ return '_0x' + m.charCodeAt(0).toString(16) + '_'; });
|
||||
};
|
||||
|
||||
var getAttr;
|
||||
|
||||
// Good browsers
|
||||
if (!getAttributeDodgy) {
|
||||
getAttr = function(attr){ return 'var '+varForAttr(attr)+' = el.getAttribute("'+attr+'");' ; };
|
||||
}
|
||||
// IE 6, 7
|
||||
else {
|
||||
// On IE 6 + 7, getAttribute still has to be called with DOM property mirror name, not attribute name. Map attributes to those names
|
||||
var getAttrIEMap = { 'class': 'className', 'for': 'htmlFor' };
|
||||
|
||||
getAttr = function(attr) {
|
||||
var ieattr = getAttrIEMap[attr] || attr;
|
||||
return 'var '+varForAttr(attr)+' = el.getAttribute("'+ieattr+'",2) || (el.getAttributeNode("'+attr+'")||{}).nodeValue;';
|
||||
};
|
||||
}
|
||||
|
||||
/**** ATTRIBUTE COMPARITORS ****/
|
||||
|
||||
var attrchecks = {
|
||||
'-': '!K',
|
||||
'=': 'K != "V"',
|
||||
'!=': 'K == "V"',
|
||||
'~=': '_WS_K.indexOf(" V ") == -1',
|
||||
'^=': '!K || K.indexOf("V") != 0',
|
||||
'*=': '!K || K.indexOf("V") == -1',
|
||||
'$=': '!K || K.substr(K.length-"V".length) != "V"'
|
||||
};
|
||||
|
||||
/**** STATE TRACKER ****/
|
||||
|
||||
var State = $.selector.State = Base.extend({
|
||||
init: function(){
|
||||
this.reset();
|
||||
},
|
||||
reset: function() {
|
||||
this.attrs = {}; this.wsattrs = {};
|
||||
},
|
||||
|
||||
prev: function(){
|
||||
this.reset();
|
||||
if (hasElementTraversal) return 'el = el.previousElementSibling';
|
||||
return 'while((el = el.previousSibling) && el.nodeType != 1) {}';
|
||||
},
|
||||
next: function() {
|
||||
this.reset();
|
||||
if (hasElementTraversal) return 'el = el.nextElementSibling';
|
||||
return 'while((el = el.nextSibling) && el.nodeType != 1) {}';
|
||||
},
|
||||
prevLoop: function(body){
|
||||
this.reset();
|
||||
if (hasElementTraversal) return join([ 'while(el = el.previousElementSibling){', body]);
|
||||
return join([
|
||||
'while(el = el.previousSibling){',
|
||||
'if (el.nodeType != 1) continue;',
|
||||
body
|
||||
]);
|
||||
},
|
||||
parent: function() {
|
||||
this.reset();
|
||||
return 'el = el.parentNode;';
|
||||
},
|
||||
parentLoop: function(body) {
|
||||
this.reset();
|
||||
return join([
|
||||
'while((el = el.parentNode) && el.nodeType == 1){',
|
||||
body,
|
||||
'}'
|
||||
]);
|
||||
},
|
||||
|
||||
uses_attr: function(attr) {
|
||||
if (this.attrs[attr]) return;
|
||||
this.attrs[attr] = true;
|
||||
return getAttr(attr);
|
||||
},
|
||||
uses_wsattr: function(attr) {
|
||||
if (this.wsattrs[attr]) return;
|
||||
this.wsattrs[attr] = true;
|
||||
return join([this.uses_attr(attr), 'var _WS_'+varForAttr(attr)+' = " "+'+varForAttr(attr)+'+" ";']);
|
||||
},
|
||||
|
||||
save: function(lbl) {
|
||||
return 'var el'+lbl+' = el;';
|
||||
},
|
||||
restore: function(lbl) {
|
||||
this.reset();
|
||||
return 'el = el'+lbl+';';
|
||||
}
|
||||
});
|
||||
|
||||
/**** PSEUDO-CLASS DETAILS ****/
|
||||
|
||||
var pseudoclschecks = {
|
||||
'first-child': join([
|
||||
'var cel = el;',
|
||||
'while(cel = cel.previousSibling){ if (cel.nodeType === 1) BAD; }'
|
||||
]),
|
||||
'last-child': join([
|
||||
'var cel = el;',
|
||||
'while(cel = cel.nextSibling){ if (cel.nodeType === 1) BAD; }'
|
||||
]),
|
||||
'nth-child': function(a,b) {
|
||||
var get_i = join([
|
||||
'var i = 1, cel = el;',
|
||||
'while(cel = cel.previousSibling){',
|
||||
'if (cel.nodeType === 1) i++;',
|
||||
'}'
|
||||
]);
|
||||
|
||||
if (a == 0) return join([
|
||||
get_i,
|
||||
'if (i- '+b+' != 0) BAD;'
|
||||
]);
|
||||
else if (b == 0 && a >= 0) return join([
|
||||
get_i,
|
||||
'if (i%'+a+' != 0 || i/'+a+' < 0) BAD;'
|
||||
]);
|
||||
else if (b == 0 && a < 0) return join([
|
||||
'BAD;'
|
||||
]);
|
||||
else return join([
|
||||
get_i,
|
||||
'if ((i- '+b+')%'+a+' != 0 || (i- '+b+')/'+a+' < 0) BAD;'
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
// Needs to refence contents of object, so must be injected after definition
|
||||
pseudoclschecks['only-child'] = join([
|
||||
pseudoclschecks['first-child'],
|
||||
pseudoclschecks['last-child']
|
||||
]);
|
||||
|
||||
/**** SimpleSelector ****/
|
||||
|
||||
$.selector.SimpleSelector.addMethod('compile', function(el) {
|
||||
var js = [];
|
||||
|
||||
/* Check against element name */
|
||||
if (this.tag && this.tag != '*') {
|
||||
js[js.length] = 'if (el.tagName != "'+this.tag.toUpperCase()+'") BAD;';
|
||||
}
|
||||
|
||||
/* Check against ID */
|
||||
if (this.id) {
|
||||
js[js.length] = el.uses_attr('id');
|
||||
js[js.length] = 'if (_id !== "'+this.id+'") BAD;';
|
||||
}
|
||||
|
||||
/* Build className checking variable */
|
||||
if (this.classes.length) {
|
||||
js[js.length] = el.uses_wsattr('class');
|
||||
|
||||
/* Check against class names */
|
||||
$.each(this.classes, function(i, cls){
|
||||
js[js.length] = 'if (_WS__class.indexOf(" '+cls+' ") == -1) BAD;';
|
||||
});
|
||||
}
|
||||
|
||||
/* Check against attributes */
|
||||
$.each(this.attrs, function(i, attr){
|
||||
js[js.length] = (attr[1] == '~=') ? el.uses_wsattr(attr[0]) : el.uses_attr(attr[0]);
|
||||
var check = attrchecks[ attr[1] || '-' ];
|
||||
check = check.replace( /K/g, varForAttr(attr[0])).replace( /V/g, attr[2] && attr[2].match(STARTS_WITH_QUOTES) ? attr[2].slice(1,-1) : attr[2] );
|
||||
js[js.length] = 'if ('+check+') BAD;';
|
||||
});
|
||||
|
||||
/* Check against nots */
|
||||
$.each(this.nots, function(i, not){
|
||||
var lbl = ++lbl_id;
|
||||
var func = join([
|
||||
'l'+lbl+':{',
|
||||
not.compile(el).replace(BAD, 'break l'+lbl).replace(GOOD, 'BAD'),
|
||||
'}'
|
||||
]);
|
||||
|
||||
if (!(not instanceof $.selector.SimpleSelector)) func = join([
|
||||
el.save(lbl),
|
||||
func,
|
||||
el.restore(lbl)
|
||||
]);
|
||||
|
||||
js[js.length] = func;
|
||||
});
|
||||
|
||||
/* Check against pseudo-classes */
|
||||
$.each(this.pseudo_classes, function(i, pscls){
|
||||
var check = pseudoclschecks[pscls[0]];
|
||||
if (check) {
|
||||
js[js.length] = ( typeof check == 'function' ? check.apply(this, pscls[1]) : check );
|
||||
}
|
||||
else if (check = $.find.selectors.filters[pscls[0]]) {
|
||||
if (funcToString) {
|
||||
js[js.length] = funcToString(check).replace(/elem/g,'el').replace(/return([^;]+);/,'if (!($1)) BAD;');
|
||||
}
|
||||
else {
|
||||
js[js.length] = 'if (!$.find.selectors.filters.'+pscls[0]+'(el)) BAD;';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
js[js.length] = 'GOOD';
|
||||
|
||||
/* Pass */
|
||||
return join(js);
|
||||
});
|
||||
|
||||
var lbl_id = 0;
|
||||
/** Turns an compiled fragment into the first part of a combination */
|
||||
function as_subexpr(f) {
|
||||
if (f.complex)
|
||||
return join([
|
||||
'l'+(++lbl_id)+':{',
|
||||
f.replace(GOOD, 'break l'+lbl_id),
|
||||
'}'
|
||||
]);
|
||||
else
|
||||
return f.replace(GOOD, '');
|
||||
}
|
||||
|
||||
var combines = {
|
||||
' ': function(el, f1, f2) {
|
||||
return join_complex([
|
||||
f2,
|
||||
'while(true){',
|
||||
el.parent(),
|
||||
'if (!el || el.nodeType !== 1) BAD;',
|
||||
f1.compile(el).replace(BAD, 'continue'),
|
||||
'}'
|
||||
]);
|
||||
},
|
||||
|
||||
'>': function(el, f1, f2) {
|
||||
return join([
|
||||
f2,
|
||||
el.parent(),
|
||||
'if (!el || el.nodeType !== 1) BAD;',
|
||||
f1.compile(el)
|
||||
]);
|
||||
},
|
||||
|
||||
'~': function(el, f1, f2) {
|
||||
return join_complex([
|
||||
f2,
|
||||
el.prevLoop(),
|
||||
f1.compile(el).replace(BAD, 'continue'),
|
||||
'}',
|
||||
'BAD;'
|
||||
]);
|
||||
},
|
||||
|
||||
'+': function(el, f1, f2) {
|
||||
return join([
|
||||
f2,
|
||||
el.prev(),
|
||||
'if (!el) BAD;',
|
||||
f1.compile(el)
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
$.selector.Selector.addMethod('compile', function(el) {
|
||||
var l = this.parts.length;
|
||||
|
||||
var expr = this.parts[--l].compile(el);
|
||||
while (l) {
|
||||
var combinator = this.parts[--l];
|
||||
expr = combines[combinator](el, this.parts[--l], as_subexpr(expr));
|
||||
}
|
||||
|
||||
return expr;
|
||||
});
|
||||
|
||||
$.selector.SelectorsGroup.addMethod('compile', function(el) {
|
||||
var expr = [], lbl = ++lbl_id;
|
||||
|
||||
for (var i=0; i < this.parts.length; i++) {
|
||||
expr[expr.length] = join([
|
||||
i == 0 ? el.save(lbl) : el.restore(lbl),
|
||||
'l'+lbl+'_'+i+':{',
|
||||
this.parts[i].compile(el).replace(BAD, 'break l'+lbl+'_'+i),
|
||||
'}'
|
||||
]);
|
||||
}
|
||||
|
||||
expr[expr.length] = 'BAD;';
|
||||
return join(expr);
|
||||
});
|
||||
|
||||
$.selector.SelectorBase.addMethod('matches', function(el){
|
||||
this.matches = new Function('el', join([
|
||||
'if (!el) return false;',
|
||||
this.compile(new State()).replace(BAD, 'return false').replace(GOOD, 'return true')
|
||||
]));
|
||||
return this.matches(el);
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.focusinout.js */
|
||||
|
||||
(function($){
|
||||
|
||||
/**
|
||||
* Add focusin and focusout support to bind and live for browers other than IE. Designed to be usable in a delegated fashion (like $.live)
|
||||
* Copyright (c) 2007 Jörn Zaefferer
|
||||
*/
|
||||
$.support.focusInOut = !!($.browser.msie);
|
||||
if (!$.support.focusInOut) {
|
||||
// Emulate focusin and focusout by binding focus and blur in capturing mode
|
||||
$.each({focus: 'focusin', blur: 'focusout'}, function(original, fix){
|
||||
$.event.special[fix] = {
|
||||
setup: function(){
|
||||
if (!this.addEventListener) return false;
|
||||
this.addEventListener(original, $.event.special[fix].handler, true);
|
||||
},
|
||||
teardown: function(){
|
||||
if (!this.removeEventListener) return false;
|
||||
this.removeEventListener(original, $.event.special[fix].handler, true);
|
||||
},
|
||||
handler: function(e){
|
||||
arguments[0] = $.event.fix(e);
|
||||
arguments[0].type = fix;
|
||||
return $.event.handle.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
(function(){
|
||||
//IE has some trouble with focusout with select and keyboard navigation
|
||||
var activeFocus = null;
|
||||
|
||||
$(document)
|
||||
.bind('focusin', function(e){
|
||||
var target = e.realTarget || e.target;
|
||||
if (activeFocus && activeFocus !== target) {
|
||||
e.type = 'focusout';
|
||||
$(activeFocus).trigger(e);
|
||||
e.type = 'focusin';
|
||||
e.target = target;
|
||||
}
|
||||
activeFocus = target;
|
||||
})
|
||||
.bind('focusout', function(e){
|
||||
activeFocus = null;
|
||||
});
|
||||
})();
|
||||
|
||||
})(jQuery);;
|
||||
|
||||
|
||||
/* src/jquery.entwine.js */
|
||||
|
||||
var console;
|
||||
|
||||
(function($) {
|
||||
|
||||
var namespaces = {};
|
||||
|
||||
$.entwine = function() {
|
||||
$.fn.entwine.apply(null, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* A couple of utility functions for accessing the store outside of this closure, and for making things
|
||||
* operate in a little more easy-to-test manner
|
||||
*/
|
||||
$.extend($.entwine, {
|
||||
/**
|
||||
* Get all the namespaces. Useful for introspection? Internal interface of Namespace not guaranteed consistant
|
||||
*/
|
||||
namespaces: namespaces,
|
||||
|
||||
/**
|
||||
* Remove all entwine rules
|
||||
*/
|
||||
clear_all_rules: function() {
|
||||
// Remove proxy functions
|
||||
for (var k in $.fn) { if ($.fn[k].entwine) delete $.fn[k] ; }
|
||||
// Remove bound events - TODO: Make this pluggable, so this code can be moved to jquery.entwine.events.js
|
||||
$(document).unbind('.entwine');
|
||||
// Remove namespaces, and start over again
|
||||
namespaces = $.entwine.namespaces = {};
|
||||
},
|
||||
|
||||
WARN_LEVEL_NONE: 0,
|
||||
WARN_LEVEL_IMPORTANT: 1,
|
||||
WARN_LEVEL_BESTPRACTISE: 2,
|
||||
|
||||
/**
|
||||
* Warning level. Set to a higher level to get warnings dumped to console.
|
||||
*/
|
||||
warningLevel: 0,
|
||||
|
||||
/** Utility to optionally display warning messages depending on level */
|
||||
warn: function(message, level) {
|
||||
if (level <= $.entwine.warningLevel && console && console.warn) {
|
||||
console.warn(message);
|
||||
if (console.trace) console.trace();
|
||||
}
|
||||
},
|
||||
|
||||
warn_exception: function(where, /* optional: */ on, e) {
|
||||
if ($.entwine.WARN_LEVEL_IMPORTANT <= $.entwine.warningLevel && console && console.warn) {
|
||||
if (arguments.length == 2) { e = on; on = null; }
|
||||
|
||||
if (on) console.warn('Uncaught exception',e,'in',where,'on',on);
|
||||
else console.warn('Uncaught exception',e,'in',where);
|
||||
|
||||
if (e.stack) console.warn("Stack Trace:\n" + e.stack);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/** Stores a count of definitions, so that we can sort identical selectors by definition order */
|
||||
var rulecount = 0;
|
||||
|
||||
var Rule = Base.extend({
|
||||
init: function(selector, name) {
|
||||
this.selector = selector;
|
||||
this.specifity = selector.specifity();
|
||||
this.important = 0;
|
||||
this.name = name;
|
||||
this.rulecount = rulecount++;
|
||||
}
|
||||
});
|
||||
|
||||
Rule.compare = function(a, b) {
|
||||
var as = a.specifity, bs = b.specifity;
|
||||
|
||||
return (a.important - b.important) ||
|
||||
(as[0] - bs[0]) ||
|
||||
(as[1] - bs[1]) ||
|
||||
(as[2] - bs[2]) ||
|
||||
(a.rulecount - b.rulecount) ;
|
||||
};
|
||||
|
||||
$.entwine.RuleList = function() {
|
||||
var list = [];
|
||||
|
||||
list.addRule = function(selector, name){
|
||||
var rule = Rule(selector, name);
|
||||
|
||||
list[list.length] = rule;
|
||||
list.sort(Rule.compare);
|
||||
|
||||
return rule;
|
||||
};
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
var handlers = [];
|
||||
|
||||
/**
|
||||
* A Namespace holds all the information needed for adding entwine methods to a namespace (including the _null_ namespace)
|
||||
*/
|
||||
$.entwine.Namespace = Base.extend({
|
||||
init: function(name){
|
||||
if (name && !name.match(/^[A-Za-z0-9.]+$/)) $.entwine.warn('Entwine namespace '+name+' is not formatted as period seperated identifiers', $.entwine.WARN_LEVEL_BESTPRACTISE);
|
||||
name = name || '__base';
|
||||
|
||||
this.name = name;
|
||||
this.store = {};
|
||||
|
||||
namespaces[name] = this;
|
||||
|
||||
if (name == "__base") {
|
||||
this.injectee = $.fn;
|
||||
this.$ = $;
|
||||
}
|
||||
else {
|
||||
// We're in a namespace, so we build a Class that subclasses the jQuery Object Class to inject namespace functions into
|
||||
var subfn = function(){};
|
||||
this.injectee = subfn.prototype = new $();
|
||||
|
||||
// And then we provide an overriding $ that returns objects of our new Class, and an overriding pushStack to catch further selection building
|
||||
var bound$ = this.$ = function(a) {
|
||||
// Try the simple way first
|
||||
var jq = $.fn.init.apply(new subfn(), arguments);
|
||||
if (jq instanceof subfn) return jq;
|
||||
|
||||
// That didn't return a bound object, so now we need to copy it
|
||||
var rv = new subfn();
|
||||
rv.selector = jq.selector; rv.context = jq.context; var i = rv.length = jq.length;
|
||||
while (i--) rv[i] = jq[i];
|
||||
return rv;
|
||||
};
|
||||
this.injectee.pushStack = function(elems, name, selector){
|
||||
var ret = bound$(elems);
|
||||
|
||||
// Add the old object onto the stack (as a reference)
|
||||
ret.prevObject = this;
|
||||
ret.context = this.context;
|
||||
|
||||
if ( name === "find" ) ret.selector = this.selector + (this.selector ? " " : "") + selector;
|
||||
else if ( name ) ret.selector = this.selector + "." + name + "(" + selector + ")";
|
||||
|
||||
// Return the newly-formed element set
|
||||
return ret;
|
||||
};
|
||||
|
||||
// Copy static functions through from $ to this.$ so e.g. $.ajax still works
|
||||
// @bug, @cantfix: Any class functions added to $ after this call won't get mirrored through
|
||||
$.extend(this.$, $);
|
||||
|
||||
// We override entwine to inject the name of this namespace when defining blocks inside this namespace
|
||||
var entwine_wrapper = this.injectee.entwine = function(spacename) {
|
||||
var args = arguments;
|
||||
|
||||
if (!spacename || typeof spacename != 'string') { args = $.makeArray(args); args.unshift(name); }
|
||||
else if (spacename.charAt(0) != '.') args[0] = name+'.'+spacename;
|
||||
|
||||
return $.fn.entwine.apply(this, args);
|
||||
};
|
||||
|
||||
this.$.entwine = function() {
|
||||
entwine_wrapper.apply(null, arguments);
|
||||
};
|
||||
|
||||
for (var i = 0; i < handlers.length; i++) {
|
||||
var handler = handlers[i], builder;
|
||||
|
||||
// Inject jQuery object method overrides
|
||||
if (builder = handler.namespaceMethodOverrides) {
|
||||
var overrides = builder(this);
|
||||
for (var k in overrides) this.injectee[k] = overrides[k];
|
||||
}
|
||||
|
||||
// Inject $.entwine function overrides
|
||||
if (builder = handler.namespaceStaticOverrides) {
|
||||
var overrides = builder(this);
|
||||
for (var k in overrides) this.$.entwine[k] = overrides[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a function that does selector matching against the function list for a function name
|
||||
* Used by proxy for all calls, and by ctorProxy to handle _super calls
|
||||
* @param {String} name - name of the function as passed in the construction object
|
||||
* @param {String} funcprop - the property on the Rule object that gives the actual function to call
|
||||
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
|
||||
*/
|
||||
one: function(name, funcprop, basefunc) {
|
||||
var namespace = this;
|
||||
var funcs = this.store[name];
|
||||
|
||||
var one = function(el, args, i){
|
||||
if (i === undefined) i = funcs.length;
|
||||
while (i--) {
|
||||
if (funcs[i].selector.matches(el)) {
|
||||
var ret, tmp_i = el.i, tmp_f = el.f;
|
||||
el.i = i; el.f = one;
|
||||
try { ret = funcs[i][funcprop].apply(namespace.$(el), args); }
|
||||
finally { el.i = tmp_i; el.f = tmp_f; }
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
// If we didn't find a entwine-defined function, but there is a non-entwine function to use as a base, try that
|
||||
if (basefunc) return basefunc.apply(namespace.$(el), args);
|
||||
};
|
||||
|
||||
return one;
|
||||
},
|
||||
|
||||
/**
|
||||
* A proxy is a function attached to a callable object (either the base jQuery.fn or a subspace object) which handles
|
||||
* finding and calling the correct function for each member of the current jQuery context
|
||||
* @param {String} name - name of the function as passed in the construction object
|
||||
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
|
||||
*/
|
||||
build_proxy: function(name, basefunc) {
|
||||
var one = this.one(name, 'func', basefunc);
|
||||
|
||||
var prxy = function() {
|
||||
var rv, ctx = $(this);
|
||||
|
||||
var i = ctx.length;
|
||||
while (i--) rv = one(ctx[i], arguments);
|
||||
return rv;
|
||||
};
|
||||
|
||||
return prxy;
|
||||
},
|
||||
|
||||
bind_proxy: function(selector, name, func) {
|
||||
var rulelist = this.store[name] || (this.store[name] = $.entwine.RuleList());
|
||||
|
||||
var rule = rulelist.addRule(selector, name); rule.func = func;
|
||||
|
||||
if (!this.injectee.hasOwnProperty(name) || !this.injectee[name].entwine) {
|
||||
this.injectee[name] = this.build_proxy(name, this.injectee.hasOwnProperty(name) ? this.injectee[name] : null);
|
||||
this.injectee[name].entwine = true;
|
||||
}
|
||||
|
||||
if (!this.injectee[name].entwine) {
|
||||
$.entwine.warn('Warning: Entwine function '+name+' clashes with regular jQuery function - entwine function will not be callable directly on jQuery object', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
},
|
||||
|
||||
add: function(selector, data) {
|
||||
// For every item in the hash, try ever method handler, until one returns true
|
||||
for (var k in data) {
|
||||
var v = data[k];
|
||||
|
||||
for (var i = 0; i < handlers.length; i++) {
|
||||
if (handlers[i].bind && handlers[i].bind.call(this, selector, k, v)) break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
has: function(ctx, name) {
|
||||
var rulelist = this.store[name];
|
||||
if (!rulelist) return false;
|
||||
|
||||
/* We go forward this time, since low specifity is likely to knock out a bunch of elements quickly */
|
||||
for (var i = 0 ; i < rulelist.length; i++) {
|
||||
ctx = ctx.not(rulelist[i].selector);
|
||||
if (!ctx.length) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A handler is some javascript code that adds support for some time of key / value pair passed in the hash to the Namespace add method.
|
||||
* The default handlers provided (and included by default) are event, ctor and properties
|
||||
*/
|
||||
$.entwine.Namespace.addHandler = function(handler) {
|
||||
for (var i = 0; i < handlers.length && handlers[i].order < handler.order; i++) { /* Pass */ }
|
||||
handlers.splice(i, 0, handler);
|
||||
};
|
||||
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 50,
|
||||
|
||||
bind: function(selector, k, v){
|
||||
if ($.isFunction(v)) {
|
||||
this.bind_proxy(selector, k, v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.extend($.fn, {
|
||||
/**
|
||||
* Main entwine function. Used for new definitions, calling into a namespace (or forcing the base namespace) and entering a using block
|
||||
*
|
||||
*/
|
||||
entwine: function(spacename) {
|
||||
var i = 0;
|
||||
/* Don't actually work out selector until we try and define something on it - we might be opening a namespace on an function-traveresed object
|
||||
which have non-standard selectors like .parents(.foo).slice(0,1) */
|
||||
var selector = null;
|
||||
|
||||
/* By default we operator on the base namespace */
|
||||
var namespace = namespaces.__base || $.entwine.Namespace();
|
||||
|
||||
/* If the first argument is a string, then it's the name of a namespace. Look it up */
|
||||
if (typeof spacename == 'string') {
|
||||
if (spacename.charAt('0') == '.') spacename = spacename.substr(1);
|
||||
if (spacename) namespace = namespaces[spacename] || $.entwine.Namespace(spacename);
|
||||
i=1;
|
||||
}
|
||||
|
||||
/* All remaining arguments should either be using blocks or definition hashs */
|
||||
while (i < arguments.length) {
|
||||
var res = arguments[i++];
|
||||
|
||||
// If it's a function, call it - either it's a using block or it's a namespaced entwine definition
|
||||
if ($.isFunction(res)) {
|
||||
if (res.length != 1) $.entwine.warn('Function block inside entwine definition does not take $ argument properly', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
res = res.call(namespace.$(this), namespace.$);
|
||||
}
|
||||
|
||||
// If we have a entwine definition hash, inject it into namespace
|
||||
if (res) {
|
||||
if (selector === null) selector = this.selector ? $.selector(this.selector) : false;
|
||||
|
||||
if (selector) namespace.add(selector, res);
|
||||
else $.entwine.warn('Entwine block given to entwine call without selector. Make sure you call $(selector).entwine when defining blocks', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, return the jQuery object 'this' refers to, wrapped in the new namespace */
|
||||
return namespace.$(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls the next most specific version of the current entwine method
|
||||
*/
|
||||
_super: function(){
|
||||
var rv, i = this.length;
|
||||
while (i--) {
|
||||
var el = this[0];
|
||||
rv = el.f(el, arguments, el.i);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.entwine.dommaybechanged.js */
|
||||
|
||||
(function($){
|
||||
|
||||
/** What to call to run a function 'soon'. Normally setTimeout, but for syncronous mode we override so soon === now */
|
||||
var runSoon = window.setTimeout;
|
||||
|
||||
/** The timer handle for the asyncronous matching call */
|
||||
var check_id = null;
|
||||
|
||||
/** Fire the change event. Only fires on the document node, so bind to that */
|
||||
var triggerEvent = function() {
|
||||
$(document).triggerHandler('DOMMaybeChanged');
|
||||
check_id = null;
|
||||
};
|
||||
|
||||
$.extend($.entwine, {
|
||||
/**
|
||||
* Make onmatch and onunmatch work in synchronous mode - that is, new elements will be detected immediately after
|
||||
* the DOM manipulation that made them match. This is only really useful for during testing, since it's pretty slow
|
||||
* (otherwise we'd make it the default).
|
||||
*/
|
||||
synchronous_mode: function() {
|
||||
if (check_id) clearTimeout(check_id); check_id = null;
|
||||
runSoon = function(func, delay){ func.call(this); return null; };
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger onmatch and onunmatch now - usefull for after DOM manipulation by methods other than through jQuery.
|
||||
* Called automatically on document.ready
|
||||
*/
|
||||
triggerMatching: function() {
|
||||
matching();
|
||||
}
|
||||
});
|
||||
|
||||
function registerMutateFunction() {
|
||||
$.each(arguments, function(i,func){
|
||||
var old = $.fn[func];
|
||||
$.fn[func] = function() {
|
||||
var rv = old.apply(this, arguments);
|
||||
if (!check_id) check_id = runSoon(triggerEvent, 100);
|
||||
return rv;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function registerSetterGetterFunction() {
|
||||
$.each(arguments, function(i,func){
|
||||
var old = $.fn[func];
|
||||
$.fn[func] = function(a, b) {
|
||||
var rv = old.apply(this, arguments);
|
||||
if (!check_id && (b !== undefined || typeof a != 'string')) check_id = runSoon(triggerEvent, 100);
|
||||
return rv;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Register core DOM manipulation methods
|
||||
registerMutateFunction('append', 'prepend', 'after', 'before', 'wrap', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove');
|
||||
registerSetterGetterFunction('attr');
|
||||
|
||||
// And on DOM ready, trigger matching once
|
||||
$(function(){ triggerEvent(); });
|
||||
|
||||
})(jQuery);;
|
||||
|
||||
|
||||
/* src/jquery.entwine.events.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
/* If we are any browser other than IE or Safari, we don't have to do anything special to handle
|
||||
* onchange delegation */
|
||||
$.support.bubblingChange = !($.browser.msie || $.browser.safari);
|
||||
|
||||
/* Return true if node b is the same as, or is a descendant of, node a */
|
||||
if (document.compareDocumentPosition) {
|
||||
var is_or_contains = function(a, b) {
|
||||
return a && b && (a == b || !!(a.compareDocumentPosition(b) & 16));
|
||||
};
|
||||
}
|
||||
else {
|
||||
var is_or_contains = function(a, b) {
|
||||
return a && b && (a == b || (a.contains ? a.contains(b) : true));
|
||||
};
|
||||
}
|
||||
|
||||
/* Add the methods to handle event binding to the Namespace class */
|
||||
$.entwine.Namespace.addMethods({
|
||||
build_event_proxy: function(name) {
|
||||
var one = this.one(name, 'func');
|
||||
|
||||
var prxy = function(e, data) {
|
||||
// For events that do not bubble we manually trigger delegation (see delegate_submit below)
|
||||
// If this event is a manual trigger, the event we actually want to bubble is attached as a property of the passed event
|
||||
e = e.delegatedEvent || e;
|
||||
|
||||
var el = e.target;
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
var ret = one(el, arguments);
|
||||
if (ret !== undefined) e.result = ret;
|
||||
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
||||
|
||||
el = el.parentNode;
|
||||
}
|
||||
};
|
||||
|
||||
return prxy;
|
||||
},
|
||||
|
||||
build_mouseenterleave_proxy: function(name) {
|
||||
var one = this.one(name, 'func');
|
||||
|
||||
var prxy = function(e) {
|
||||
var el = e.target;
|
||||
var rel = e.relatedTarget;
|
||||
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
/* We know el contained target. If it also contains relatedTarget then we didn't mouseenter / leave. What's more, every ancestor will also
|
||||
contan el and rel, and so we can just stop bubbling */
|
||||
if (is_or_contains(el, rel)) break;
|
||||
|
||||
var ret = one(el, arguments);
|
||||
if (ret !== undefined) e.result = ret;
|
||||
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
||||
|
||||
el = el.parentNode;
|
||||
}
|
||||
};
|
||||
|
||||
return prxy;
|
||||
},
|
||||
|
||||
build_change_proxy: function(name) {
|
||||
var one = this.one(name, 'func');
|
||||
|
||||
var prxy = function(e) {
|
||||
var el = e.target;
|
||||
// If this is a keydown event, only worry about the enter key, since browsers only trigger onchange on enter or focus loss
|
||||
if (e.type === 'keydown' && e.keyCode !== 13) return;
|
||||
// Make sure this is event is for an input type we're interested in
|
||||
if (el.tagName !== 'INPUT' && el.tagName !== 'TEXTAREA' && el.tagName !== 'SELECT') return;
|
||||
|
||||
var $el = $(el), nowVal, oldVal = $el.data('changeVal');
|
||||
|
||||
// Detect changes on checkboxes & radiobuttons, which have different value logic. We don't use el.value, since el is part
|
||||
// of a set, and we only want to raise onchange once for a single user action.
|
||||
if (el.type == 'checkbox' || el.type == 'radio') {
|
||||
if (!el.disabled && e.type === 'click') {
|
||||
nowVal = el.checked;
|
||||
// If radio, we get two changes - the activation, and the deactivation. We only want to fire one change though
|
||||
if ((el.type === 'checkbox' || nowVal === true) && oldVal !== nowVal) e.type = 'change';
|
||||
}
|
||||
}
|
||||
// Detect changes on other input types. In this case value is OK.
|
||||
else {
|
||||
nowVal = el.value;
|
||||
if (oldVal !== undefined && oldVal !== nowVal) e.type = 'change';
|
||||
}
|
||||
|
||||
// Save the current value for next time
|
||||
if (nowVal !== undefined) $el.data('changeVal', nowVal);
|
||||
|
||||
// And if we decided that a change happened, do the actual triggering
|
||||
if (e.type == 'change') {
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
var ret = one(el, arguments);
|
||||
if (ret !== undefined) e.result = ret;
|
||||
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
||||
|
||||
el = el.parentNode;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return prxy;
|
||||
},
|
||||
|
||||
bind_event: function(selector, name, func, event) {
|
||||
var funcs = this.store[name] || (this.store[name] = $.entwine.RuleList()) ;
|
||||
var proxies = funcs.proxies || (funcs.proxies = {});
|
||||
|
||||
var rule = funcs.addRule(selector, name); rule.func = func;
|
||||
|
||||
if (!proxies[name]) {
|
||||
switch (name) {
|
||||
case 'onmouseenter':
|
||||
proxies[name] = this.build_mouseenterleave_proxy(name);
|
||||
event = 'mouseover';
|
||||
break;
|
||||
case 'onmouseleave':
|
||||
proxies[name] = this.build_mouseenterleave_proxy(name);
|
||||
event = 'mouseout';
|
||||
break;
|
||||
case 'onchange':
|
||||
if (!$.support.bubblingChange) {
|
||||
proxies[name] = this.build_change_proxy(name);
|
||||
event = 'click focusin focusout keydown';
|
||||
}
|
||||
break;
|
||||
case 'onsubmit':
|
||||
event = 'delegatedSubmit';
|
||||
break;
|
||||
case 'onfocus':
|
||||
case 'onblur':
|
||||
$.entwine.warn('Event '+event+' not supported - using focusin / focusout instead', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
|
||||
// If none of the special handlers created a proxy, use the generic proxy
|
||||
if (!proxies[name]) proxies[name] = this.build_event_proxy(name);
|
||||
|
||||
$(document).bind(event+'.entwine', proxies[name]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 40,
|
||||
|
||||
bind: function(selector, k, v){
|
||||
var match, event;
|
||||
if ($.isFunction(v) && (match = k.match(/^on(.*)/))) {
|
||||
event = match[1];
|
||||
this.bind_event(selector, k, v, event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Find all forms and bind onsubmit to trigger on the document too.
|
||||
// This is the only event that can't be grabbed via delegation
|
||||
|
||||
var form_binding_cache = $([]); // A cache for already-handled form elements
|
||||
var delegate_submit = function(e, data){
|
||||
var delegationEvent = $.Event('delegatedSubmit'); delegationEvent.delegatedEvent = e;
|
||||
return $(document).trigger(delegationEvent, data);
|
||||
};
|
||||
|
||||
$(document).bind('DOMMaybeChanged', function(){
|
||||
var forms = $('form');
|
||||
// Only bind to forms we haven't processed yet
|
||||
forms.not(form_binding_cache).bind('submit', delegate_submit);
|
||||
// Then remember the current set of forms
|
||||
form_binding_cache = forms;
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.entwine.ctors.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
/* Add the methods to handle constructor & destructor binding to the Namespace class */
|
||||
$.entwine.Namespace.addMethods({
|
||||
bind_condesc: function(selector, name, func) {
|
||||
var ctors = this.store.ctors || (this.store.ctors = $.entwine.RuleList()) ;
|
||||
|
||||
var rule;
|
||||
for (var i = 0 ; i < ctors.length; i++) {
|
||||
if (ctors[i].selector.selector == selector.selector) {
|
||||
rule = ctors[i]; break;
|
||||
}
|
||||
}
|
||||
if (!rule) {
|
||||
rule = ctors.addRule(selector, 'ctors');
|
||||
}
|
||||
|
||||
rule[name] = func;
|
||||
|
||||
if (!ctors[name+'proxy']) {
|
||||
var one = this.one('ctors', name);
|
||||
var namespace = this;
|
||||
|
||||
var proxy = function(els, i, func) {
|
||||
var j = els.length;
|
||||
while (j--) {
|
||||
var el = els[j];
|
||||
|
||||
var tmp_i = el.i, tmp_f = el.f;
|
||||
el.i = i; el.f = one;
|
||||
|
||||
try { func.call(namespace.$(el)); }
|
||||
catch(e) { $.entwine.warn_exception(name, el, e); }
|
||||
finally { el.i = tmp_i; el.f = tmp_f; }
|
||||
}
|
||||
};
|
||||
|
||||
ctors[name+'proxy'] = proxy;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 30,
|
||||
|
||||
bind: function(selector, k, v) {
|
||||
if ($.isFunction(v) && (k == 'onmatch' || k == 'onunmatch')) {
|
||||
this.bind_condesc(selector, k, v);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds all the elements that now match a different rule (or have been removed) and call onmatch on onunmatch as appropriate
|
||||
*
|
||||
* Because this has to scan the DOM, and is therefore fairly slow, this is normally triggered off a short timeout, so that
|
||||
* a series of DOM manipulations will only trigger this once.
|
||||
*
|
||||
* The downside of this is that things like:
|
||||
* $('#foo').addClass('tabs'); $('#foo').tabFunctionBar();
|
||||
* won't work.
|
||||
*/
|
||||
$(document).bind('DOMMaybeChanged', function(){
|
||||
// For every namespace
|
||||
for (var k in $.entwine.namespaces) {
|
||||
// That has constructors or destructors
|
||||
var ctors = $.entwine.namespaces[k].store.ctors;
|
||||
if (ctors) {
|
||||
|
||||
// Keep a record of elements that have matched already
|
||||
var matched = $([]), add, rem, res, rule, sel, ctor, dtor;
|
||||
// Stepping through each selector from most to least specific
|
||||
var j = ctors.length;
|
||||
while (j--) {
|
||||
// Build some quick-access variables
|
||||
rule = ctors[j];
|
||||
sel = rule.selector.selector;
|
||||
ctor = rule.onmatch;
|
||||
dtor = rule.onunmatch;
|
||||
|
||||
// Get the list of elements that match this selector, that haven't yet matched a more specific selector
|
||||
res = add = $(sel).not(matched);
|
||||
|
||||
// If this selector has a list of elements it matched against last time
|
||||
if (rule.cache) {
|
||||
// Find the ones that are extra this time
|
||||
add = res.not(rule.cache);
|
||||
if (dtor) {
|
||||
// Find the ones that are gone this time
|
||||
rem = rule.cache.not(res);
|
||||
// And call the destructor on them
|
||||
if (rem.length) ctors.onunmatchproxy(rem, j, dtor);
|
||||
}
|
||||
}
|
||||
|
||||
// Call the constructor on the newly matched ones
|
||||
if (add.length && ctor) ctors.onmatchproxy(add, j, ctor);
|
||||
|
||||
// Add these matched ones to the list tracking all elements matched so far
|
||||
matched = matched.add(res);
|
||||
// And remember this list of matching elements again this selector, so next matching we can find the unmatched ones
|
||||
ctors[j].cache = res;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.entwine.properties.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
var entwine_prepend = '__entwine!';
|
||||
|
||||
var getEntwineData = function(el, namespace, property) {
|
||||
return el.data(entwine_prepend + namespace + '!' + property);
|
||||
};
|
||||
|
||||
var setEntwineData = function(el, namespace, property, value) {
|
||||
return el.data(entwine_prepend + namespace + '!' + property, value);
|
||||
};
|
||||
|
||||
var getEntwineDataAsHash = function(el, namespace) {
|
||||
var hash = {};
|
||||
var id = jQuery.data(el[0]);
|
||||
|
||||
var matchstr = entwine_prepend + namespace + '!';
|
||||
var matchlen = matchstr.length;
|
||||
|
||||
var cache = jQuery.cache[id];
|
||||
for (var k in cache) {
|
||||
if (k.substr(0,matchlen) == matchstr) hash[k.substr(matchlen)] = cache[k];
|
||||
}
|
||||
|
||||
return hash;
|
||||
};
|
||||
|
||||
var setEntwineDataFromHash = function(el, namespace, hash) {
|
||||
for (var k in hash) setEntwineData(namespace, k, hash[k]);
|
||||
};
|
||||
|
||||
var entwineData = function(el, namespace, args) {
|
||||
switch (args.length) {
|
||||
case 0:
|
||||
return getEntwineDataAsHash(el, namespace);
|
||||
case 1:
|
||||
if (typeof args[0] == 'string') return getEntwineData(el, namespace, args[0]);
|
||||
else return setEntwineDataFromHash(el, namespace, args[0]);
|
||||
default:
|
||||
return setEntwineData(el, namespace, args[0], args[1]);
|
||||
}
|
||||
};
|
||||
|
||||
$.extend($.fn, {
|
||||
entwineData: function() {
|
||||
return entwineData(this, '__base', arguments);
|
||||
}
|
||||
});
|
||||
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 60,
|
||||
|
||||
bind: function(selector, k, v) {
|
||||
if (k.charAt(0) != k.charAt(0).toUpperCase()) $.entwine.warn('Entwine property '+k+' does not start with a capital letter', $.entwine.WARN_LEVEL_BESTPRACTISE);
|
||||
|
||||
// Create the getters and setters
|
||||
|
||||
var getterName = 'get'+k;
|
||||
var setterName = 'set'+k;
|
||||
|
||||
this.bind_proxy(selector, getterName, function() { return this.entwineData(k) || v ; });
|
||||
this.bind_proxy(selector, setterName, function(v){ return this.entwineData(k, v); });
|
||||
|
||||
// Get the get and set proxies we just created
|
||||
|
||||
var getter = this.injectee[getterName];
|
||||
var setter = this.injectee[setterName];
|
||||
|
||||
// And bind in the jQuery-style accessor
|
||||
|
||||
this.bind_proxy(selector, k, function(v){ return (arguments.length == 1 ? setter : getter).call(this, v) ; });
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
namespaceMethodOverrides: function(namespace){
|
||||
return {
|
||||
entwineData: function() {
|
||||
return entwineData(this, namespace.name, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
||||
|
||||
/* src/jquery.entwine.legacy.js */
|
||||
|
||||
(function($) {
|
||||
|
||||
// Adds back concrete methods for backwards compatibility
|
||||
$.concrete = $.entwine;
|
||||
$.fn.concrete = $.fn.entwine;
|
||||
$.fn.concreteData = $.fn.entwineData;
|
||||
|
||||
// Use addHandler to hack in the namespace.$.concrete equivilent to the namespace.$.entwine namespace-injection
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 100,
|
||||
bind: function(selector, k, v) { return false; },
|
||||
|
||||
namespaceMethodOverrides: function(namespace){
|
||||
namespace.$.concrete = namespace.$.entwine;
|
||||
namespace.injectee.concrete = namespace.injectee.entwine;
|
||||
namespace.injectee.concreteData = namespace.injectee.entwineData;
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
;
|
||||
|
30
thirdparty/jquery-entwine/spec/legacy/spec-dist.html
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<html>
|
||||
<head>
|
||||
<!-- spec-dist is the same as spec, but runs on the distribution version of the library, to make sure no problems were introduced during building -->
|
||||
<link type="text/css" rel="stylesheet" href="../../vendor/jspec/lib/jspec.css" />
|
||||
<script src="../../vendor/jquery-1.3.2.js"></script>
|
||||
<script src="../../vendor/jspec/lib/jspec.js"></script>
|
||||
<script src="../../vendor/jspec/lib/jspec.jquery.js"></script>
|
||||
|
||||
<script src="../../dist/jquery.entwine-dist.js"></script>
|
||||
|
||||
<script>
|
||||
function runSuites() {
|
||||
JSpec
|
||||
.exec('spec.concrete.basics.js')
|
||||
.exec('spec.concrete.namespaces.js')
|
||||
.exec('spec.concrete.super.js')
|
||||
.exec('spec.concrete.events.js')
|
||||
.exec('spec.concrete.ctors.js')
|
||||
.exec('spec.concrete.properties.js')
|
||||
.run()
|
||||
.report()
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="jspec" onLoad="runSuites();">
|
||||
<div id="jspec-top"><h2 id="jspec-title">JSpec <em><script>document.write(JSpec.version)</script></em></h2></div>
|
||||
<div id="jspec"><div class="loading"></div></div>
|
||||
<div id="jspec-bottom"></div>
|
||||
</body>
|
||||
</html>
|
@ -11,7 +11,7 @@ describe 'Concrete'
|
||||
|
||||
before_each
|
||||
$.concrete.clear_all_rules();
|
||||
$('#dom_test').html('<div id="a" class="a b c"></div><div id="b" class="c d e"></div>');
|
||||
$('#dom_test').html('<div id="a" class="a b c" data-fieldtype="foo"></div><div id="b" class="c d e"></div>');
|
||||
end
|
||||
|
||||
it 'can attach and call a base function'
|
||||
@ -20,6 +20,13 @@ describe 'Concrete'
|
||||
});
|
||||
$('.a').foo().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'can attach and call a base function on a selector using a data attribute selection'
|
||||
$('[data-fieldtype=foo]').concrete({
|
||||
foo: function(){return this.attr('id');}
|
||||
});
|
||||
$('.a').foo().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'can attach and call several base functions'
|
||||
$('#a').concrete({
|
@ -10,12 +10,12 @@ describe 'Concrete'
|
||||
end
|
||||
|
||||
before_each
|
||||
$.concrete.synchronous_mode();
|
||||
$.concrete.synchronous_mode();
|
||||
$.concrete.clear_all_rules()
|
||||
$('#dom_test').html('<div id="a" class="a b c"></div>')
|
||||
end
|
||||
|
||||
it 'calls onfoo when foo triggered'
|
||||
it 'calls onfoo when foo triggered'
|
||||
var a = 0;
|
||||
$('#a').concrete({onfoo: function(){a = 1;} });
|
||||
a.should.equal 0
|
||||
@ -63,6 +63,50 @@ describe 'Concrete'
|
||||
$('#a').trigger('foo')
|
||||
[a, b].should.eql [2, 1]
|
||||
end
|
||||
|
||||
|
||||
it 'passes event object'
|
||||
var event;
|
||||
$('#a').concrete({onfoo: function(e){event = e;} });
|
||||
$('#a').trigger('foo');
|
||||
event.should.have_prop 'type', 'foo'
|
||||
$(event.target).should.have_attr 'id', 'a'
|
||||
end
|
||||
|
||||
it 'delegates submit events to forms'
|
||||
var a = 0;
|
||||
$('<form class="foo" action="javascript:undefined">').appendTo('#dom_test');
|
||||
|
||||
$('.foo').concrete({onsubmit: function(e, d){a = 1;} });
|
||||
|
||||
a.should.eql 0
|
||||
$('.foo').trigger('submit');
|
||||
a.should.eql 1
|
||||
end
|
||||
|
||||
describe 'can pass event data'
|
||||
it 'on custom events'
|
||||
var data;
|
||||
$('#a').concrete({onfoo: function(e, d){data = d;} });
|
||||
$('#a').trigger('foo', {cheese: 'burger'});
|
||||
data.cheese.should.eql 'burger'
|
||||
end
|
||||
|
||||
it 'on normal events'
|
||||
var data;
|
||||
$('#a').concrete({onclick: function(e, d){data = d;} });
|
||||
$('#a').trigger('click', {finger: 'left'});
|
||||
data.finger.should.eql 'left'
|
||||
end
|
||||
|
||||
it 'on submit'
|
||||
var data;
|
||||
|
||||
$('<form class="foo" action="javascript:undefined">').appendTo('#dom_test');
|
||||
$('.foo').concrete({onsubmit: function(e, d){data = d; return false;} })
|
||||
|
||||
$('.foo').trigger('submit', {cheese: 'burger'});
|
||||
data.cheese.should.eql 'burger'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -27,7 +27,7 @@ describe 'Concrete'
|
||||
$('.a').setFoo(1);
|
||||
$('.a').getFoo().should.equal 1
|
||||
end
|
||||
|
||||
|
||||
it 'can define a default value'
|
||||
$('#a').concrete({
|
||||
Foo: 1
|
||||
@ -73,5 +73,30 @@ describe 'Concrete'
|
||||
$('.a').concreteData('Foo').should.equal 4
|
||||
$('.a').concrete('test').concreteData('Foo').should.equal 8
|
||||
end
|
||||
|
||||
describe 'jQuery style accessors'
|
||||
it 'can define and get a basic property'
|
||||
$('#a').concrete({
|
||||
Foo: null
|
||||
});
|
||||
$('.a').Foo().should.be_null
|
||||
end
|
||||
|
||||
it 'can define and set a basic property'
|
||||
$('#a').concrete({
|
||||
Foo: null
|
||||
});
|
||||
$('.a').Foo(1);
|
||||
$('.a').Foo().should.equal 1
|
||||
end
|
||||
|
||||
it 'can define a default value'
|
||||
$('#a').concrete({
|
||||
Foo: 1
|
||||
});
|
||||
$('.a').Foo().should.equal 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -10,35 +10,35 @@ describe 'Concrete'
|
||||
|
||||
before_each
|
||||
$.concrete.clear_all_rules()
|
||||
$('#dom_test').html('<div id="a" class="a b c"></div><div id="b" class="c d e"></div>')
|
||||
$('#dom_test').html('<div id="a" class="a b c">Foo</div><div id="b" class="c d e">Bar</div>')
|
||||
end
|
||||
|
||||
it 'can call the super function'
|
||||
var a = 1;
|
||||
var a = 1;
|
||||
$('#a').concrete({
|
||||
foo: function(){a *= 2;}
|
||||
});
|
||||
$('#a.a').concrete({
|
||||
foo: function(){a += 2; this._super();}
|
||||
});
|
||||
$('#a').foo();
|
||||
a.should.equal 6
|
||||
$('#a').foo();
|
||||
a.should.equal 6
|
||||
end
|
||||
|
||||
|
||||
it 'super to a non-existant class should be ignored'
|
||||
var a = 1;
|
||||
var a = 1;
|
||||
$('#a').concrete({
|
||||
foo: function(){a *= 2; this._super();}
|
||||
});
|
||||
$('#a.a').concrete({
|
||||
foo: function(){a += 2; this._super();}
|
||||
});
|
||||
$('#a').foo();
|
||||
a.should.equal 6
|
||||
$('#a').foo();
|
||||
a.should.equal 6
|
||||
end
|
||||
|
||||
|
||||
it 'can call super from two different functions without screwing up what super points to'
|
||||
var list = [];
|
||||
var list = [];
|
||||
$('#a').concrete({
|
||||
foo: function(){ list.push('foo'); this.bar(); },
|
||||
bar: function(){ list.push('bar'); }
|
||||
@ -47,8 +47,20 @@ describe 'Concrete'
|
||||
foo: function(){ list.push('foo2'); this._super(); list.push('foo2'); this._super(); },
|
||||
bar: function(){ list.push('bar2'); this._super(); }
|
||||
});
|
||||
$('#a').foo();
|
||||
list.should.eql [ 'foo2', 'foo', 'bar2', 'bar', 'foo2', 'foo', 'bar2', 'bar' ]
|
||||
$('#a').foo();
|
||||
list.should.eql [ 'foo2', 'foo', 'bar2', 'bar', 'foo2', 'foo', 'bar2', 'bar' ]
|
||||
end
|
||||
|
||||
it 'can override (and call via super) a non-concrete jquery function'
|
||||
var a = 1
|
||||
$('#a').concrete({
|
||||
text: function(){ a = this._super(); }
|
||||
});
|
||||
|
||||
$('#a').text();
|
||||
a.should.equal 'Foo'
|
||||
|
||||
$('#b').text().should.equal 'Bar'
|
||||
end
|
||||
end
|
||||
end
|
39
thirdparty/jquery-entwine/spec/legacy/spec.html
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
<html>
|
||||
<head>
|
||||
<link type="text/css" rel="stylesheet" href="../../vendor/jspec/lib/jspec.css" />
|
||||
<script src="../../vendor/jquery-1.3.2.js"></script>
|
||||
<script src="../../vendor/jspec/lib/jspec.js"></script>
|
||||
<script src="../../vendor/jspec/lib/jspec.jquery.js"></script>
|
||||
|
||||
<script src="../../vendor/jquery.selector/jquery.class.js"></script>
|
||||
<script src="../../vendor/jquery.selector/jquery.selector.js"></script>
|
||||
<script src="../../vendor/jquery.selector/jquery.selector.specifity.js"></script>
|
||||
<script src="../../vendor/jquery.selector/jquery.selector.matches.js"></script>
|
||||
|
||||
<script src="../../src/jquery.entwine.js"></script>
|
||||
<script src="../../src/jquery.entwine.dommaybechanged.js"></script>
|
||||
<script src="../../src/jquery.entwine.events.js"></script>
|
||||
<script src="../../src/jquery.entwine.ctors.js"></script>
|
||||
<script src="../../src/jquery.entwine.properties.js"></script>
|
||||
<script src="../../src/jquery.entwine.legacy.js"></script>
|
||||
|
||||
<script>
|
||||
function runSuites() {
|
||||
JSpec
|
||||
.exec('spec.concrete.basics.js')
|
||||
.exec('spec.concrete.namespaces.js')
|
||||
.exec('spec.concrete.super.js')
|
||||
.exec('spec.concrete.events.js')
|
||||
.exec('spec.concrete.ctors.js')
|
||||
.exec('spec.concrete.properties.js')
|
||||
.run()
|
||||
.report()
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="jspec" onLoad="runSuites();">
|
||||
<div id="jspec-top"><h2 id="jspec-title">JSpec <em><script>document.write(JSpec.version)</script></em></h2></div>
|
||||
<div id="jspec"><div class="loading"></div></div>
|
||||
<div id="jspec-bottom"></div>
|
||||
</body>
|
||||
</html>
|
@ -6,17 +6,17 @@
|
||||
<script src="../vendor/jspec/lib/jspec.js"></script>
|
||||
<script src="../vendor/jspec/lib/jspec.jquery.js"></script>
|
||||
|
||||
<script src="../dist/jquery.concrete-latest.js"></script>
|
||||
<script src="../dist/jquery.entwine-dist.js"></script>
|
||||
|
||||
<script>
|
||||
function runSuites() {
|
||||
JSpec
|
||||
.exec('spec.concrete.basics.js')
|
||||
.exec('spec.concrete.namespaces.js')
|
||||
.exec('spec.concrete.super.js')
|
||||
.exec('spec.concrete.events.js')
|
||||
.exec('spec.concrete.ctors.js')
|
||||
.exec('spec.concrete.properties.js')
|
||||
.exec('spec.entwine.basics.js')
|
||||
.exec('spec.entwine.namespaces.js')
|
||||
.exec('spec.entwine.super.js')
|
||||
.exec('spec.entwine.events.js')
|
||||
.exec('spec.entwine.ctors.js')
|
||||
.exec('spec.entwine.properties.js')
|
||||
.run()
|
||||
.report()
|
||||
}
|
85
thirdparty/jquery-entwine/spec/spec.entwine.basics.js
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
|
||||
describe 'Entwine'
|
||||
describe 'Basics'
|
||||
before
|
||||
$.entwine.warningLevel = $.entwine.WARN_LEVEL_BESTPRACTISE;
|
||||
$('body').append('<div id="dom_test"></div>');
|
||||
end
|
||||
after
|
||||
$('#dom_test').remove();
|
||||
end
|
||||
|
||||
before_each
|
||||
$.entwine.clear_all_rules();
|
||||
$('#dom_test').html('<div id="a" class="a b c" data-fieldtype="foo"></div><div id="b" class="c d e"></div>');
|
||||
end
|
||||
|
||||
it 'can attach and call a base function'
|
||||
$('#a').entwine({
|
||||
foo: function(){return this.attr('id');}
|
||||
});
|
||||
$('.a').foo().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'can attach and call a base function on a selector using a data attribute selection'
|
||||
$('[data-fieldtype=foo]').entwine({
|
||||
foo: function(){return this.attr('id');}
|
||||
});
|
||||
$('.a').foo().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'can attach and call several base functions'
|
||||
$('#a').entwine({
|
||||
foo: function(){return 'foo_' + this.attr('id');},
|
||||
bar: function(){return 'bar_' + this.attr('id');}
|
||||
});
|
||||
$('.a').foo().should.equal 'foo_a'
|
||||
$('.a').bar().should.equal 'bar_a'
|
||||
end
|
||||
|
||||
it 'can attach and call a namespaced function'
|
||||
$.entwine('bar', function($){
|
||||
$('#a').entwine({
|
||||
foo: function(){return this.attr('id');}
|
||||
});
|
||||
});
|
||||
$('.a').entwine('bar').foo().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'can attach and call a nested namespaced function'
|
||||
$.entwine('qux.baz.bar', function($){
|
||||
$('#a').entwine({
|
||||
foo: function(){return this.attr('id');}
|
||||
});
|
||||
});
|
||||
$('.a').entwine('qux.baz.bar').foo().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'can call two functions on two elements'
|
||||
var res = []
|
||||
$('#a').entwine({
|
||||
foo: function(){res.push(this.attr('id'));}
|
||||
});
|
||||
$('#b.c').entwine({
|
||||
foo: function(){res.push(this.attr('id'));}
|
||||
});
|
||||
$('#dom_test div').foo();
|
||||
res.should.eql ['b', 'a']
|
||||
end
|
||||
|
||||
it 'can call two namespaced functions on two elements'
|
||||
var res = []
|
||||
$.entwine('bar', function($){
|
||||
$('#a').entwine({
|
||||
foo: function(){res.push(this.attr('id'));}
|
||||
});
|
||||
$('#b.c').entwine({
|
||||
foo: function(){res.push(this.attr('id'));}
|
||||
});
|
||||
});
|
||||
$('#dom_test div').entwine('bar').foo();
|
||||
res.should.eql ['b', 'a']
|
||||
end
|
||||
|
||||
end
|
||||
end
|
68
thirdparty/jquery-entwine/spec/spec.entwine.ctors.js
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
describe 'Entwine'
|
||||
describe 'Ctors'
|
||||
|
||||
before
|
||||
$('body').append('<div id="dom_test"></div>')
|
||||
end
|
||||
|
||||
after
|
||||
$('#dom_test').remove()
|
||||
end
|
||||
|
||||
before_each
|
||||
$.entwine.synchronous_mode();
|
||||
$.entwine.clear_all_rules()
|
||||
$('#dom_test').html('<div id="a" class="a b c"></div>')
|
||||
end
|
||||
|
||||
it 'calls onmatch when new element created'
|
||||
var a = false;
|
||||
$('#b').entwine({onmatch: function(){a = true;} });
|
||||
a.should.be_false
|
||||
$('#a').after('<div id="b"></div>');
|
||||
a.should.be_true
|
||||
end
|
||||
|
||||
it 'calls onunmatch when new element deleted'
|
||||
var a = 0;
|
||||
$('#b').entwine({onmatch: function(){a = 1;}, onunmatch: function(){a = 2;} });
|
||||
a.should.equal 0
|
||||
$('#a').after('<div id="b"></div>');
|
||||
a.should.equal 1
|
||||
$('#b').remove();
|
||||
a.should.equal 2
|
||||
end
|
||||
|
||||
it 'calls onmatch when ruleset matches after class added'
|
||||
var a = 0;
|
||||
$('#a.foo').entwine({onmatch: function(){a = 1;} });
|
||||
a.should.equal 0
|
||||
$('#a').addClass('foo');
|
||||
a.should.equal 1
|
||||
end
|
||||
|
||||
it 'calls onmatch in both direct and namespaced onmatch, does not call less specific onmatch'
|
||||
var a = 0, b=0, c=0, d=0;
|
||||
$('.foo').entwine({onmatch: function(){a = 1;}})
|
||||
$('.foo').entwine('bar', function($){return{onmatch: function(){b = 1;}}})
|
||||
$('#a.foo').entwine({onmatch: function(){c = 1;}})
|
||||
$('#a.foo').entwine('bar', function($){return{onmatch: function(){d = 1}}})
|
||||
[a, b, c, d].should.eql [0, 0, 0, 0]
|
||||
$('#a').addClass('foo');
|
||||
[a, b, c, d].should.eql [0, 0, 1, 1]
|
||||
end
|
||||
|
||||
it 'calls onmatch in both direct and namespaced onmatch, super works as expected'
|
||||
var a = 0, b=0, c=0, d=0;
|
||||
$('.foo').entwine({onmatch: function(){a += 1;}})
|
||||
$('.foo').entwine('bar', function($){return{onmatch: function(){b += 1;}}})
|
||||
$('#a.foo').entwine({onmatch: function(){this._super(); c = 1; this._super();}})
|
||||
$('#a.foo').entwine('bar', function($){return{onmatch: function(){this._super(); d = 1; this._super();}}})
|
||||
[a, b, c, d].should.eql [0, 0, 0, 0]
|
||||
$('#a').addClass('foo');
|
||||
[a, b, c, d].should.eql [2, 2, 1, 1]
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
112
thirdparty/jquery-entwine/spec/spec.entwine.events.js
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
describe 'Entwine'
|
||||
describe 'Events'
|
||||
|
||||
before
|
||||
$('body').append('<div id="dom_test"></div>')
|
||||
end
|
||||
|
||||
after
|
||||
$('#dom_test').remove()
|
||||
end
|
||||
|
||||
before_each
|
||||
$.entwine.synchronous_mode();
|
||||
$.entwine.clear_all_rules()
|
||||
$('#dom_test').html('<div id="a" class="a b c"></div>')
|
||||
end
|
||||
|
||||
it 'calls onfoo when foo triggered'
|
||||
var a = 0;
|
||||
$('#a').entwine({onfoo: function(){a = 1;} });
|
||||
a.should.equal 0
|
||||
$('#a').trigger('foo');
|
||||
a.should.equal 1
|
||||
end
|
||||
|
||||
it 'only calls most specific onfoo when foo triggered'
|
||||
var a = 0, b = 0;
|
||||
$('#a.a').entwine({onfoo: function(){a = 1;} });
|
||||
$('#a').entwine({onfoo: function(){b = 1;} });
|
||||
a.should.equal 0
|
||||
b.should.equal 0
|
||||
$('#a').trigger('foo');
|
||||
a.should.equal 1
|
||||
b.should.equal 0
|
||||
end
|
||||
|
||||
it 'calls namespaced onfoo when foo triggered'
|
||||
var a = 0;
|
||||
$('#a').entwine('bar', function($){return{onfoo: function(){a = 1;} }});
|
||||
a.should.equal 0
|
||||
$('#a').trigger('foo');
|
||||
a.should.equal 1
|
||||
end
|
||||
|
||||
it 'calls most specific namespaced onfoo and most specific non-namespaced onfoo when foo triggered'
|
||||
var a = 0, b = 0, c = 0, d = 0;
|
||||
$('#a.a').entwine({onfoo: function(){a = 1;} });
|
||||
$('#a').entwine({onfoo: function(){b = 1;} });
|
||||
$('#a.a').entwine('bar', function($){return{onfoo: function(){c = 1;} }});
|
||||
$('#a').entwine('bar', function($){return{onfoo: function(){d = 1;} }});
|
||||
[a, b, c, d].should.eql [0, 0, 0, 0]
|
||||
|
||||
$('#a').trigger('foo');
|
||||
[a, b, c, d].should.eql [1, 0, 1, 0]
|
||||
end
|
||||
|
||||
it 'calls up correctly on _super'
|
||||
var a = 0, b = 0;
|
||||
$('#a').entwine({onfoo: function(){a += 1;} });
|
||||
$('#a.a').entwine({onfoo: function(){this._super(); b += 1; this._super();} });
|
||||
|
||||
[a, b].should.eql [0, 0]
|
||||
$('#a').trigger('foo')
|
||||
[a, b].should.eql [2, 1]
|
||||
end
|
||||
|
||||
it 'passes event object'
|
||||
var event;
|
||||
$('#a').entwine({onfoo: function(e){event = e;} });
|
||||
$('#a').trigger('foo');
|
||||
event.should.have_prop 'type', 'foo'
|
||||
$(event.target).should.have_attr 'id', 'a'
|
||||
end
|
||||
|
||||
it 'delegates submit events to forms'
|
||||
var a = 0;
|
||||
$('<form class="foo" action="javascript:undefined">').appendTo('#dom_test');
|
||||
|
||||
$('.foo').entwine({onsubmit: function(e, d){a = 1;} });
|
||||
|
||||
a.should.eql 0
|
||||
$('.foo').trigger('submit');
|
||||
a.should.eql 1
|
||||
end
|
||||
|
||||
describe 'can pass event data'
|
||||
it 'on custom events'
|
||||
var data;
|
||||
$('#a').entwine({onfoo: function(e, d){data = d;} });
|
||||
$('#a').trigger('foo', {cheese: 'burger'});
|
||||
data.cheese.should.eql 'burger'
|
||||
end
|
||||
|
||||
it 'on normal events'
|
||||
var data;
|
||||
$('#a').entwine({onclick: function(e, d){data = d;} });
|
||||
$('#a').trigger('click', {finger: 'left'});
|
||||
data.finger.should.eql 'left'
|
||||
end
|
||||
|
||||
it 'on submit'
|
||||
var data;
|
||||
|
||||
$('<form class="foo" action="javascript:undefined">').appendTo('#dom_test');
|
||||
$('.foo').entwine({onsubmit: function(e, d){data = d; return false;} })
|
||||
|
||||
$('.foo').trigger('submit', {cheese: 'burger'});
|
||||
data.cheese.should.eql 'burger'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
246
thirdparty/jquery-entwine/spec/spec.entwine.namespaces.js
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
|
||||
describe 'Entwine'
|
||||
describe 'Namespaces'
|
||||
before
|
||||
$('body').append('<div id="dom_test"></div>')
|
||||
end
|
||||
after
|
||||
$('#dom_test').remove()
|
||||
end
|
||||
|
||||
before_each
|
||||
$.entwine.synchronous_mode();
|
||||
$.entwine.clear_all_rules()
|
||||
$('#dom_test').html('<div id="a" class="a b c"></div><div id="b" class="c d e"></div>')
|
||||
end
|
||||
|
||||
it 'namespaced functions work (single definition mode)'
|
||||
$('#a').entwine('bar', function($){return{
|
||||
bar: function(){return 'a';}
|
||||
}})
|
||||
$('#a').entwine('bar').bar().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'namespaced functions work (block definition mode)'
|
||||
$.entwine('zap', function($){
|
||||
$('#a').entwine({
|
||||
bar: function(){return 'a';}
|
||||
})
|
||||
});
|
||||
$('#a').entwine('zap').bar().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'double-namespaced functions work (block definition mode)'
|
||||
$.entwine('zap', function($){
|
||||
$.entwine('pow', function($){
|
||||
$('#a').entwine({
|
||||
bar: function(){return 'a';}
|
||||
})
|
||||
})
|
||||
})
|
||||
$('#a').entwine('zap.pow').bar().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'revert to base namespacing work (block definition mode)'
|
||||
$.entwine('zap', function($){
|
||||
$.entwine('.pow', function($){
|
||||
$('#a').entwine({
|
||||
bar: function(){return 'a';}
|
||||
})
|
||||
})
|
||||
})
|
||||
$('#a').entwine('pow').bar().should.equal 'a'
|
||||
end
|
||||
|
||||
it 'internal to namespace, will look up functions in namespace before in base'
|
||||
var res = []
|
||||
$('#a').entwine({
|
||||
foo: function(){res.push(1);},
|
||||
bar: function(){res.push(2); this.foo();}
|
||||
})
|
||||
$('#a').entwine('bar', function($){return{
|
||||
foo: function(){res.push(3);},
|
||||
bar: function(){res.push(4); $(this).foo();}
|
||||
}})
|
||||
|
||||
$('#dom_test div').bar();
|
||||
res.should.eql [2, 1]
|
||||
$('#dom_test div').entwine('bar').bar();
|
||||
res.should.eql [2, 1, 4, 3]
|
||||
end
|
||||
|
||||
it 'internal to namespace, will look up functions in namespace before in base, even in closure'
|
||||
var res = []
|
||||
$('#a').entwine({
|
||||
foo: function(){res.push(1);},
|
||||
bar: function(){res.push(2); this.foo();}
|
||||
})
|
||||
$('#a').entwine('bar', function($){return{
|
||||
foo: function(){res.push(3);},
|
||||
bar: function(){res.push(4); $('#a').each(function(){ $(this).foo(); })}
|
||||
}})
|
||||
|
||||
$('#dom_test div').bar();
|
||||
res.should.eql [2, 1]
|
||||
$('#dom_test div').entwine('bar').bar();
|
||||
res.should.eql [2, 1, 4, 3]
|
||||
end
|
||||
|
||||
it 'internal to namespace, will look up functions in namespace before in base, even in onmatch'
|
||||
var res = []
|
||||
$('#a').entwine({
|
||||
foo: function(){res.push(1);},
|
||||
bar: function(){res.push(2); this.foo();}
|
||||
})
|
||||
$('#a').entwine('bar', function($){return{
|
||||
foo: function(){res.push(3);}
|
||||
}})
|
||||
$('#a.d').entwine('bar', function($){return{
|
||||
onmatch: function(){res.push(4); this.foo();}
|
||||
}})
|
||||
|
||||
$('#dom_test div').bar();
|
||||
res.should.eql [2, 1]
|
||||
|
||||
$('#a').addClass('d');
|
||||
res.should.eql [2, 1, 4, 3]
|
||||
end
|
||||
|
||||
it 'internal to namespace, will look up functions in base when not present in namespace'
|
||||
var res = []
|
||||
$('#a').entwine({
|
||||
foo: function(){res.push(1);}
|
||||
})
|
||||
$('#a').entwine('bar', function($){return{
|
||||
bar: function(){res.push(2); this.foo();}
|
||||
}})
|
||||
$('#dom_test div').entwine('bar').bar();
|
||||
res.should.eql [2, 1]
|
||||
end
|
||||
|
||||
it 'internal to namespace, will not look up functions in base if present in namespace, even when not applicable to selector'
|
||||
var res = []
|
||||
$('#a').entwine('bar', function($){return{
|
||||
foo: function(){this.bar();}
|
||||
}})
|
||||
$('#a').entwine({
|
||||
bar: function(){res.push(1);}
|
||||
})
|
||||
$('span').entwine('bar', function($){return{
|
||||
bar: function(){res.push(2);}
|
||||
}})
|
||||
|
||||
$('#a').entwine('bar').foo()
|
||||
res.should.eql []
|
||||
end
|
||||
|
||||
it 'internal to namespace, can be directed to base namespace'
|
||||
var res = []
|
||||
$('#a').entwine({
|
||||
foo: function(){res.push(1);},
|
||||
bar: function(){res.push(2); this.foo();}
|
||||
})
|
||||
$('#a').entwine('bar', function($){return{
|
||||
foo: function(){res.push(3);},
|
||||
bar: function(){res.push(4); this.foo(); this.entwine('.').foo();}
|
||||
}})
|
||||
$('#dom_test div').bar();
|
||||
res.should.eql [2, 1]
|
||||
$('#dom_test div').entwine('bar').bar();
|
||||
res.should.eql [2, 1, 4, 3, 1]
|
||||
end
|
||||
|
||||
it 'internal to namespace, will look up functions in namespace called the same as a regular jQuery base function'
|
||||
var res = []
|
||||
$('#a').entwine('bar', function($){return{
|
||||
load: function(){res.push(1);},
|
||||
bar: function(){res.push(2); this.load();}
|
||||
}})
|
||||
$('#dom_test div').entwine('bar').bar();
|
||||
res.should.eql [2, 1]
|
||||
end
|
||||
|
||||
it 'internal to namespace, can be directed to regular jQuery base function'
|
||||
var res = []
|
||||
$.fn.testy = function(){ res.push(1); }
|
||||
$('#a').entwine('bar', function($){return{
|
||||
testy: function(){res.push(3);},
|
||||
bar: function(){res.push(2); this.entwine('.').testy();}
|
||||
}})
|
||||
$('#dom_test div').entwine('bar').bar();
|
||||
res.should.eql [2, 1]
|
||||
end
|
||||
|
||||
it 'internal to namespace, can be directed to sub namespace'
|
||||
var res = []
|
||||
$.entwine('zap', function($){
|
||||
$('#a').entwine({
|
||||
foo: function(){ res.push(1); this.entwine('pow').bar(); }
|
||||
})
|
||||
|
||||
$.entwine('pow', function($){
|
||||
$('#a').entwine({
|
||||
bar: function(){ res.push(2); }
|
||||
})
|
||||
})
|
||||
})
|
||||
$('#dom_test div').entwine('zap').foo();
|
||||
res.should.eql [1, 2]
|
||||
end
|
||||
|
||||
it 'internal to namespace, can be directed to unrelated namespace'
|
||||
var res = []
|
||||
$.entwine('zap', function($){
|
||||
$('#a').entwine({
|
||||
foo: function(){ res.push(1); this.entwine('.pow').bar(); }
|
||||
})
|
||||
|
||||
$.entwine('pow', function($){
|
||||
$('#a').entwine({
|
||||
bar: function(){ res.push(2); }
|
||||
})
|
||||
})
|
||||
})
|
||||
$.entwine('pow', function($){
|
||||
$('#a').entwine({
|
||||
bar: function(){ res.push(3); }
|
||||
})
|
||||
})
|
||||
|
||||
$('#dom_test div').entwine('zap').foo();
|
||||
res.should.eql [1, 3]
|
||||
end
|
||||
|
||||
it 'a function passed out of a namespace will remember its namespace'
|
||||
var res = []
|
||||
var func = function(func) {
|
||||
func.call($('#a, #b'));
|
||||
}
|
||||
$('#a, #b').entwine('bar', function($){return{
|
||||
zap: function(){res.push($(this).attr('id'));},
|
||||
bar: function(){res.push(2); func(this.zap);}
|
||||
}})
|
||||
$('#dom_test #a').entwine('bar').bar();
|
||||
res.should.eql [2, 'b', 'a']
|
||||
end
|
||||
|
||||
it 'using block functions'
|
||||
var res = []
|
||||
$('#a').entwine({
|
||||
foo: function(){res.push(1);}
|
||||
})
|
||||
$('#a').entwine('bar', function($){return{
|
||||
foo: function(){res.push(3);}
|
||||
}})
|
||||
|
||||
$('#dom_test div').foo();
|
||||
res.should.eql [1]
|
||||
|
||||
$('#dom_test div').entwine('bar', function($){
|
||||
$(this).foo();
|
||||
})
|
||||
res.should.eql [1, 3]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
102
thirdparty/jquery-entwine/spec/spec.entwine.properties.js
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
|
||||
describe 'Entwine'
|
||||
describe 'Properties'
|
||||
before
|
||||
$('body').append('<div id="dom_test"></div>')
|
||||
end
|
||||
after
|
||||
$('#dom_test').remove()
|
||||
end
|
||||
|
||||
before_each
|
||||
$.entwine.clear_all_rules()
|
||||
$('#dom_test').html('<div id="a" class="a b c"></div><div id="b" class="b c"></div>')
|
||||
end
|
||||
|
||||
it 'can define and get a basic property'
|
||||
$('#a').entwine({
|
||||
Foo: null
|
||||
});
|
||||
$('.a').getFoo().should.be_null
|
||||
end
|
||||
|
||||
it 'can define and set a basic property'
|
||||
$('#a').entwine({
|
||||
Foo: null
|
||||
});
|
||||
$('.a').setFoo(1);
|
||||
$('.a').getFoo().should.equal 1
|
||||
end
|
||||
|
||||
it 'can define a default value'
|
||||
$('#a').entwine({
|
||||
Foo: 1
|
||||
});
|
||||
$('.a').getFoo().should.equal 1
|
||||
end
|
||||
|
||||
it 'should manage proprties in namespaces without clashing'
|
||||
$('#a').entwine({
|
||||
Foo: 1
|
||||
});
|
||||
|
||||
$.entwine('test', function($){
|
||||
$('#a').entwine({
|
||||
Foo: 2
|
||||
});
|
||||
});
|
||||
|
||||
$('.a').getFoo().should.equal 1
|
||||
$('.a').entwine('test').getFoo().should.equal 2
|
||||
|
||||
$('.a').setFoo(4);
|
||||
$('.a').entwine('test').setFoo(8);
|
||||
|
||||
$('.a').getFoo().should.equal 4
|
||||
$('.a').entwine('test').getFoo().should.equal 8
|
||||
end
|
||||
|
||||
it 'should manage directly setting proprties in namespaces without clashing'
|
||||
$('#a').entwine({
|
||||
Foo: null
|
||||
});
|
||||
|
||||
$.entwine('test', function($){
|
||||
$('#a').entwine({
|
||||
Foo: null
|
||||
});
|
||||
});
|
||||
|
||||
$('.a').entwineData('Foo', 4);
|
||||
$('.a').entwine('test').entwineData('Foo', 8);
|
||||
|
||||
$('.a').entwineData('Foo').should.equal 4
|
||||
$('.a').entwine('test').entwineData('Foo').should.equal 8
|
||||
end
|
||||
|
||||
describe 'jQuery style accessors'
|
||||
it 'can define and get a basic property'
|
||||
$('#a').entwine({
|
||||
Foo: null
|
||||
});
|
||||
$('.a').Foo().should.be_null
|
||||
end
|
||||
|
||||
it 'can define and set a basic property'
|
||||
$('#a').entwine({
|
||||
Foo: null
|
||||
});
|
||||
$('.a').Foo(1);
|
||||
$('.a').Foo().should.equal 1
|
||||
end
|
||||
|
||||
it 'can define a default value'
|
||||
$('#a').entwine({
|
||||
Foo: 1
|
||||
});
|
||||
$('.a').Foo().should.equal 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
66
thirdparty/jquery-entwine/spec/spec.entwine.super.js
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
describe 'Entwine'
|
||||
describe 'Super'
|
||||
before
|
||||
$('body').append('<div id="dom_test"></div>')
|
||||
end
|
||||
after
|
||||
$('#dom_test').remove()
|
||||
end
|
||||
|
||||
before_each
|
||||
$.entwine.clear_all_rules()
|
||||
$('#dom_test').html('<div id="a" class="a b c">Foo</div><div id="b" class="c d e">Bar</div>')
|
||||
end
|
||||
|
||||
it 'can call the super function'
|
||||
var a = 1;
|
||||
$('#a').entwine({
|
||||
foo: function(){a *= 2;}
|
||||
});
|
||||
$('#a.a').entwine({
|
||||
foo: function(){a += 2; this._super();}
|
||||
});
|
||||
$('#a').foo();
|
||||
a.should.equal 6
|
||||
end
|
||||
|
||||
it 'super to a non-existant class should be ignored'
|
||||
var a = 1;
|
||||
$('#a').entwine({
|
||||
foo: function(){a *= 2; this._super();}
|
||||
});
|
||||
$('#a.a').entwine({
|
||||
foo: function(){a += 2; this._super();}
|
||||
});
|
||||
$('#a').foo();
|
||||
a.should.equal 6
|
||||
end
|
||||
|
||||
it 'can call super from two different functions without screwing up what super points to'
|
||||
var list = [];
|
||||
$('#a').entwine({
|
||||
foo: function(){ list.push('foo'); this.bar(); },
|
||||
bar: function(){ list.push('bar'); }
|
||||
});
|
||||
$('#a.a').entwine({
|
||||
foo: function(){ list.push('foo2'); this._super(); list.push('foo2'); this._super(); },
|
||||
bar: function(){ list.push('bar2'); this._super(); }
|
||||
});
|
||||
$('#a').foo();
|
||||
list.should.eql [ 'foo2', 'foo', 'bar2', 'bar', 'foo2', 'foo', 'bar2', 'bar' ]
|
||||
end
|
||||
|
||||
it 'can override (and call via super) a non-entwine jquery function'
|
||||
var a = 1
|
||||
$('#a').entwine({
|
||||
text: function(){ a = this._super(); }
|
||||
});
|
||||
|
||||
$('#a').text();
|
||||
a.should.equal 'Foo'
|
||||
|
||||
$('#b').text().should.equal 'Bar'
|
||||
end
|
||||
end
|
||||
end
|
@ -10,21 +10,21 @@
|
||||
<script src="../vendor/jquery.selector/jquery.selector.specifity.js"></script>
|
||||
<script src="../vendor/jquery.selector/jquery.selector.matches.js"></script>
|
||||
|
||||
<script src="../src/jquery.concrete.js"></script>
|
||||
<script src="../src/jquery.concrete.dommaybechanged.js"></script>
|
||||
<script src="../src/jquery.concrete.events.js"></script>
|
||||
<script src="../src/jquery.concrete.ctors.js"></script>
|
||||
<script src="../src/jquery.concrete.properties.js"></script>
|
||||
<script src="../src/jquery.entwine.js"></script>
|
||||
<script src="../src/jquery.entwine.dommaybechanged.js"></script>
|
||||
<script src="../src/jquery.entwine.events.js"></script>
|
||||
<script src="../src/jquery.entwine.ctors.js"></script>
|
||||
<script src="../src/jquery.entwine.properties.js"></script>
|
||||
|
||||
<script>
|
||||
function runSuites() {
|
||||
JSpec
|
||||
.exec('spec.concrete.basics.js')
|
||||
.exec('spec.concrete.namespaces.js')
|
||||
.exec('spec.concrete.super.js')
|
||||
.exec('spec.concrete.events.js')
|
||||
.exec('spec.concrete.ctors.js')
|
||||
.exec('spec.concrete.properties.js')
|
||||
.exec('spec.entwine.basics.js')
|
||||
.exec('spec.entwine.namespaces.js')
|
||||
.exec('spec.entwine.super.js')
|
||||
.exec('spec.entwine.events.js')
|
||||
.exec('spec.entwine.ctors.js')
|
||||
.exec('spec.entwine.properties.js')
|
||||
.run()
|
||||
.report()
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
(function($) {
|
||||
|
||||
/* Add the methods to handle constructor & destructor binding to the Namespace class */
|
||||
$.concrete.Namespace.addMethods({
|
||||
$.entwine.Namespace.addMethods({
|
||||
bind_condesc: function(selector, name, func) {
|
||||
var ctors = this.store.ctors || (this.store.ctors = $.concrete.RuleList()) ;
|
||||
var ctors = this.store.ctors || (this.store.ctors = $.entwine.RuleList()) ;
|
||||
|
||||
var rule;
|
||||
for (var i = 0 ; i < ctors.length; i++) {
|
||||
@ -28,17 +28,19 @@
|
||||
|
||||
var tmp_i = el.i, tmp_f = el.f;
|
||||
el.i = i; el.f = one;
|
||||
try { func.call(namespace.$(el)); }
|
||||
catch(e) { el.i = tmp_i; el.f = tmp_f; }
|
||||
|
||||
try { func.call(namespace.$(el)); }
|
||||
catch(e) { $.entwine.warn_exception(name, el, e); }
|
||||
finally { el.i = tmp_i; el.f = tmp_f; }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ctors[name+'proxy'] = proxy;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.concrete.Namespace.addHandler({
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 30,
|
||||
|
||||
bind: function(selector, k, v) {
|
||||
@ -61,29 +63,35 @@
|
||||
*/
|
||||
$(document).bind('DOMMaybeChanged', function(){
|
||||
// For every namespace
|
||||
for (var k in $.concrete.namespaces) {
|
||||
for (var k in $.entwine.namespaces) {
|
||||
// That has constructors or destructors
|
||||
var ctors = $.concrete.namespaces[k].store.ctors;
|
||||
var ctors = $.entwine.namespaces[k].store.ctors;
|
||||
if (ctors) {
|
||||
|
||||
// Keep a record of elements that have matched already
|
||||
var matched = $([]), match, add, rem;
|
||||
var matched = $([]), add, rem, res, rule, sel, ctor, dtor;
|
||||
// Stepping through each selector from most to least specific
|
||||
var j = ctors.length;
|
||||
while (j--) {
|
||||
// Build some quick-acccess variables
|
||||
var sel = ctors[j].selector.selector, ctor = ctors[j].onmatch; dtor = ctors[j].onunmatch;
|
||||
// Build some quick-access variables
|
||||
rule = ctors[j];
|
||||
sel = rule.selector.selector;
|
||||
ctor = rule.onmatch;
|
||||
dtor = rule.onunmatch;
|
||||
|
||||
// Get the list of elements that match this selector, that haven't yet matched a more specific selector
|
||||
res = add = $(sel).not(matched);
|
||||
|
||||
// If this selector has a list of elements it matched against last time
|
||||
if (ctors[j].cache) {
|
||||
// If this selector has a list of elements it matched against last time
|
||||
if (rule.cache) {
|
||||
// Find the ones that are extra this time
|
||||
add = res.not(ctors[j].cache);
|
||||
// Find the ones that are gone this time
|
||||
rem = ctors[j].cache.not(res);
|
||||
// And call the desctructor on them
|
||||
if (rem.length && dtor) ctors.onunmatchproxy(rem, j, dtor);
|
||||
add = res.not(rule.cache);
|
||||
if (dtor) {
|
||||
// Find the ones that are gone this time
|
||||
rem = rule.cache.not(res);
|
||||
// And call the destructor on them
|
||||
if (rem.length) ctors.onunmatchproxy(rem, j, dtor);
|
||||
}
|
||||
}
|
||||
|
||||
// Call the constructor on the newly matched ones
|
||||
@ -96,7 +104,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
@ -10,9 +10,9 @@
|
||||
var triggerEvent = function() {
|
||||
$(document).triggerHandler('DOMMaybeChanged');
|
||||
check_id = null;
|
||||
}
|
||||
};
|
||||
|
||||
$.extend($.concrete, {
|
||||
$.extend($.entwine, {
|
||||
/**
|
||||
* Make onmatch and onunmatch work in synchronous mode - that is, new elements will be detected immediately after
|
||||
* the DOM manipulation that made them match. This is only really useful for during testing, since it's pretty slow
|
||||
@ -20,7 +20,7 @@
|
||||
*/
|
||||
synchronous_mode: function() {
|
||||
if (check_id) clearTimeout(check_id); check_id = null;
|
||||
runSoon = function(func, delay){ func.call(this); return null; }
|
||||
runSoon = function(func, delay){ func.call(this); return null; };
|
||||
},
|
||||
|
||||
/**
|
||||
@ -39,8 +39,8 @@
|
||||
var rv = old.apply(this, arguments);
|
||||
if (!check_id) check_id = runSoon(triggerEvent, 100);
|
||||
return rv;
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function registerSetterGetterFunction() {
|
||||
@ -50,8 +50,8 @@
|
||||
var rv = old.apply(this, arguments);
|
||||
if (!check_id && (b !== undefined || typeof a != 'string')) check_id = runSoon(triggerEvent, 100);
|
||||
return rv;
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Register core DOM manipulation methods
|
||||
@ -59,6 +59,6 @@
|
||||
registerSetterGetterFunction('attr');
|
||||
|
||||
// And on DOM ready, trigger matching once
|
||||
$(function(){ triggerEvent(); })
|
||||
$(function(){ triggerEvent(); });
|
||||
|
||||
})(jQuery);
|
@ -8,24 +8,26 @@
|
||||
if (document.compareDocumentPosition) {
|
||||
var is_or_contains = function(a, b) {
|
||||
return a && b && (a == b || !!(a.compareDocumentPosition(b) & 16));
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
var is_or_contains = function(a, b) {
|
||||
return a && b && (a == b || (a.contains ? a.contains(b) : true));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Add the methods to handle event binding to the Namespace class */
|
||||
$.concrete.Namespace.addMethods({
|
||||
$.entwine.Namespace.addMethods({
|
||||
build_event_proxy: function(name) {
|
||||
var one = this.one(name, 'func');
|
||||
|
||||
var prxy = function(e, originalevent) {
|
||||
e = originalevent || e;
|
||||
var prxy = function(e, data) {
|
||||
// For events that do not bubble we manually trigger delegation (see delegate_submit below)
|
||||
// If this event is a manual trigger, the event we actually want to bubble is attached as a property of the passed event
|
||||
e = e.delegatedEvent || e;
|
||||
|
||||
var el = e.target;
|
||||
while (el && el != document && !e.isPropagationStopped()) {
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
var ret = one(el, arguments);
|
||||
if (ret !== undefined) e.result = ret;
|
||||
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
||||
@ -44,7 +46,7 @@
|
||||
var el = e.target;
|
||||
var rel = e.relatedTarget;
|
||||
|
||||
while (el && el != document && !e.isPropagationStopped()) {
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
/* We know el contained target. If it also contains relatedTarget then we didn't mouseenter / leave. What's more, every ancestor will also
|
||||
contan el and rel, and so we can just stop bubbling */
|
||||
if (is_or_contains(el, rel)) break;
|
||||
@ -92,7 +94,7 @@
|
||||
|
||||
// And if we decided that a change happened, do the actual triggering
|
||||
if (e.type == 'change') {
|
||||
while (el && el != document && !e.isPropagationStopped()) {
|
||||
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
||||
var ret = one(el, arguments);
|
||||
if (ret !== undefined) e.result = ret;
|
||||
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
||||
@ -106,7 +108,7 @@
|
||||
},
|
||||
|
||||
bind_event: function(selector, name, func, event) {
|
||||
var funcs = this.store[name] || (this.store[name] = $.concrete.RuleList()) ;
|
||||
var funcs = this.store[name] || (this.store[name] = $.entwine.RuleList()) ;
|
||||
var proxies = funcs.proxies || (funcs.proxies = {});
|
||||
|
||||
var rule = funcs.addRule(selector, name); rule.func = func;
|
||||
@ -128,19 +130,22 @@
|
||||
}
|
||||
break;
|
||||
case 'onsubmit':
|
||||
event = 'delegated_submit';
|
||||
event = 'delegatedSubmit';
|
||||
break;
|
||||
case 'onfocus':
|
||||
case 'onblur':
|
||||
$.concrete.warn('Event '+event+' not supported - using focusin / focusout instead', $.concrete.WARN_LEVEL_IMPORTANT);
|
||||
$.entwine.warn('Event '+event+' not supported - using focusin / focusout instead', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
|
||||
// If none of the special handlers created a proxy, use the generic proxy
|
||||
if (!proxies[name]) proxies[name] = this.build_event_proxy(name);
|
||||
$(document).bind(event, proxies[name]);
|
||||
|
||||
$(document).bind(event+'.entwine', proxies[name]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.concrete.Namespace.addHandler({
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 40,
|
||||
|
||||
bind: function(selector, k, v){
|
||||
@ -153,10 +158,14 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Find all forms and bind onsubmit to trigger on the document too. This is the only event that can't be grabbed via delegation.
|
||||
// Find all forms and bind onsubmit to trigger on the document too.
|
||||
// This is the only event that can't be grabbed via delegation
|
||||
|
||||
var form_binding_cache = $([]); // A cache for already-handled form elements
|
||||
var delegate_submit = function(e){ $(document).triggerHandler('delegated_submit', e); } // The function that handles the delegation
|
||||
var delegate_submit = function(e, data){
|
||||
var delegationEvent = $.Event('delegatedSubmit'); delegationEvent.delegatedEvent = e;
|
||||
return $(document).trigger(delegationEvent, data);
|
||||
};
|
||||
|
||||
$(document).bind('DOMMaybeChanged', function(){
|
||||
var forms = $('form');
|
@ -4,28 +4,30 @@ var console;
|
||||
|
||||
var namespaces = {};
|
||||
|
||||
$.concrete = function() {
|
||||
$.fn.concrete.apply(null, arguments);
|
||||
}
|
||||
$.entwine = function() {
|
||||
$.fn.entwine.apply(null, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* A couple of utility functions for accessing the store outside of this closure, and for making things
|
||||
* operate in a little more easy-to-test manner
|
||||
*/
|
||||
$.extend($.concrete, {
|
||||
$.extend($.entwine, {
|
||||
/**
|
||||
* Get all the namespaces. Useful for introspection? Internal interface of Namespace not guaranteed consistant
|
||||
*/
|
||||
namespaces: namespaces,
|
||||
|
||||
/**
|
||||
* Remove all concrete rules
|
||||
* Remove all entwine rules
|
||||
*/
|
||||
clear_all_rules: function() {
|
||||
// Remove proxy functions
|
||||
for (var k in $.fn) { if ($.fn[k].concrete) delete $.fn[k] ; }
|
||||
for (var k in $.fn) { if ($.fn[k].entwine) delete $.fn[k] ; }
|
||||
// Remove bound events - TODO: Make this pluggable, so this code can be moved to jquery.entwine.events.js
|
||||
$(document).unbind('.entwine');
|
||||
// Remove namespaces, and start over again
|
||||
namespaces = $.concrete.namespaces = {};
|
||||
namespaces = $.entwine.namespaces = {};
|
||||
},
|
||||
|
||||
WARN_LEVEL_NONE: 0,
|
||||
@ -39,10 +41,21 @@ var console;
|
||||
|
||||
/** Utility to optionally display warning messages depending on level */
|
||||
warn: function(message, level) {
|
||||
if (level <= $.concrete.warningLevel && console && console.log) {
|
||||
if (level <= $.entwine.warningLevel && console && console.warn) {
|
||||
console.warn(message);
|
||||
if (console.trace) console.trace();
|
||||
}
|
||||
},
|
||||
|
||||
warn_exception: function(where, /* optional: */ on, e) {
|
||||
if ($.entwine.WARN_LEVEL_IMPORTANT <= $.entwine.warningLevel && console && console.warn) {
|
||||
if (arguments.length == 2) { e = on; on = null; }
|
||||
|
||||
if (on) console.warn('Uncaught exception',e,'in',where,'on',on);
|
||||
else console.warn('Uncaught exception',e,'in',where);
|
||||
|
||||
if (e.stack) console.warn("Stack Trace:\n" + e.stack);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -68,9 +81,9 @@ var console;
|
||||
(as[1] - bs[1]) ||
|
||||
(as[2] - bs[2]) ||
|
||||
(a.rulecount - b.rulecount) ;
|
||||
}
|
||||
};
|
||||
|
||||
$.concrete.RuleList = function() {
|
||||
$.entwine.RuleList = function() {
|
||||
var list = [];
|
||||
|
||||
list.addRule = function(selector, name){
|
||||
@ -83,16 +96,16 @@ var console;
|
||||
};
|
||||
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
var handlers = [];
|
||||
|
||||
/**
|
||||
* A Namespace holds all the information needed for adding concrete methods to a namespace (including the _null_ namespace)
|
||||
* A Namespace holds all the information needed for adding entwine methods to a namespace (including the _null_ namespace)
|
||||
*/
|
||||
$.concrete.Namespace = Base.extend({
|
||||
$.entwine.Namespace = Base.extend({
|
||||
init: function(name){
|
||||
if (name && !name.match(/^[A-Za-z0-9.]+$/)) $.concrete.warn('Concrete namespace '+name+' is not formatted as period seperated identifiers', $.concrete.WARN_LEVEL_BESTPRACTISE);
|
||||
if (name && !name.match(/^[A-Za-z0-9.]+$/)) $.entwine.warn('Entwine namespace '+name+' is not formatted as period seperated identifiers', $.entwine.WARN_LEVEL_BESTPRACTISE);
|
||||
name = name || '__base';
|
||||
|
||||
this.name = name;
|
||||
@ -101,12 +114,12 @@ var console;
|
||||
namespaces[name] = this;
|
||||
|
||||
if (name == "__base") {
|
||||
this.injectee = $.fn
|
||||
this.injectee = $.fn;
|
||||
this.$ = $;
|
||||
}
|
||||
else {
|
||||
// We're in a namespace, so we build a Class that subclasses the jQuery Object Class to inject namespace functions into
|
||||
var subfn = function(){}
|
||||
var subfn = function(){};
|
||||
this.injectee = subfn.prototype = new $();
|
||||
|
||||
// And then we provide an overriding $ that returns objects of our new Class, and an overriding pushStack to catch further selection building
|
||||
@ -120,7 +133,7 @@ var console;
|
||||
rv.selector = jq.selector; rv.context = jq.context; var i = rv.length = jq.length;
|
||||
while (i--) rv[i] = jq[i];
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
this.injectee.pushStack = function(elems, name, selector){
|
||||
var ret = bound$(elems);
|
||||
|
||||
@ -133,25 +146,25 @@ var console;
|
||||
|
||||
// Return the newly-formed element set
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// Copy static functions through from $ to this.$ so e.g. $.ajax still works
|
||||
// @bug, @cantfix: Any class functions added to $ after this call won't get mirrored through
|
||||
$.extend(this.$, $);
|
||||
|
||||
// We override concrete to inject the name of this namespace when defining blocks inside this namespace
|
||||
var concrete_wrapper = this.injectee.concrete = function(spacename) {
|
||||
// We override entwine to inject the name of this namespace when defining blocks inside this namespace
|
||||
var entwine_wrapper = this.injectee.entwine = function(spacename) {
|
||||
var args = arguments;
|
||||
|
||||
if (!spacename || typeof spacename != 'string') { args = $.makeArray(args); args.unshift(name); }
|
||||
else if (spacename.charAt(0) != '.') args[0] = name+'.'+spacename;
|
||||
|
||||
return $.fn.concrete.apply(this, args);
|
||||
}
|
||||
return $.fn.entwine.apply(this, args);
|
||||
};
|
||||
|
||||
this.$.concrete = function() {
|
||||
concrete_wrapper.apply(null, arguments);
|
||||
}
|
||||
this.$.entwine = function() {
|
||||
entwine_wrapper.apply(null, arguments);
|
||||
};
|
||||
|
||||
for (var i = 0; i < handlers.length; i++) {
|
||||
var handler = handlers[i], builder;
|
||||
@ -162,10 +175,10 @@ var console;
|
||||
for (var k in overrides) this.injectee[k] = overrides[k];
|
||||
}
|
||||
|
||||
// Inject $.concrete function overrides
|
||||
// Inject $.entwine function overrides
|
||||
if (builder = handler.namespaceStaticOverrides) {
|
||||
var overrides = builder(this);
|
||||
for (var k in overrides) this.$.concrete[k] = overrides[k];
|
||||
for (var k in overrides) this.$.entwine[k] = overrides[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -176,8 +189,9 @@ var console;
|
||||
* Used by proxy for all calls, and by ctorProxy to handle _super calls
|
||||
* @param {String} name - name of the function as passed in the construction object
|
||||
* @param {String} funcprop - the property on the Rule object that gives the actual function to call
|
||||
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
|
||||
*/
|
||||
one: function(name, funcprop) {
|
||||
one: function(name, funcprop, basefunc) {
|
||||
var namespace = this;
|
||||
var funcs = this.store[name];
|
||||
|
||||
@ -192,7 +206,9 @@ var console;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we didn't find a entwine-defined function, but there is a non-entwine function to use as a base, try that
|
||||
if (basefunc) return basefunc.apply(namespace.$(el), args);
|
||||
};
|
||||
|
||||
return one;
|
||||
},
|
||||
@ -201,9 +217,10 @@ var console;
|
||||
* A proxy is a function attached to a callable object (either the base jQuery.fn or a subspace object) which handles
|
||||
* finding and calling the correct function for each member of the current jQuery context
|
||||
* @param {String} name - name of the function as passed in the construction object
|
||||
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
|
||||
*/
|
||||
build_proxy: function(name) {
|
||||
var one = this.one(name, 'func');
|
||||
build_proxy: function(name, basefunc) {
|
||||
var one = this.one(name, 'func', basefunc);
|
||||
|
||||
var prxy = function() {
|
||||
var rv, ctx = $(this);
|
||||
@ -217,17 +234,17 @@ var console;
|
||||
},
|
||||
|
||||
bind_proxy: function(selector, name, func) {
|
||||
var rulelist = this.store[name] || (this.store[name] = $.concrete.RuleList());
|
||||
var rulelist = this.store[name] || (this.store[name] = $.entwine.RuleList());
|
||||
|
||||
var rule = rulelist.addRule(selector, name); rule.func = func;
|
||||
|
||||
if (!this.injectee.hasOwnProperty(name)) {
|
||||
this.injectee[name] = this.build_proxy(name);
|
||||
this.injectee[name].concrete = true;
|
||||
if (!this.injectee.hasOwnProperty(name) || !this.injectee[name].entwine) {
|
||||
this.injectee[name] = this.build_proxy(name, this.injectee.hasOwnProperty(name) ? this.injectee[name] : null);
|
||||
this.injectee[name].entwine = true;
|
||||
}
|
||||
|
||||
if (!this.injectee[name].concrete) {
|
||||
$.concrete.warn('Warning: Concrete function '+name+' clashes with regular jQuery function - concrete function will not be callable directly on jQuery object', $.concrete.WARN_LEVEL_IMPORTANT);
|
||||
if (!this.injectee[name].entwine) {
|
||||
$.entwine.warn('Warning: Entwine function '+name+' clashes with regular jQuery function - entwine function will not be callable directly on jQuery object', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
},
|
||||
|
||||
@ -259,12 +276,12 @@ var console;
|
||||
* A handler is some javascript code that adds support for some time of key / value pair passed in the hash to the Namespace add method.
|
||||
* The default handlers provided (and included by default) are event, ctor and properties
|
||||
*/
|
||||
$.concrete.Namespace.addHandler = function(handler) {
|
||||
$.entwine.Namespace.addHandler = function(handler) {
|
||||
for (var i = 0; i < handlers.length && handlers[i].order < handler.order; i++) { /* Pass */ }
|
||||
handlers.splice(i, 0, handler);
|
||||
}
|
||||
};
|
||||
|
||||
$.concrete.Namespace.addHandler({
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 50,
|
||||
|
||||
bind: function(selector, k, v){
|
||||
@ -277,20 +294,22 @@ var console;
|
||||
|
||||
$.extend($.fn, {
|
||||
/**
|
||||
* Main concrete function. Used for new definitions, calling into a namespace (or forcing the base namespace) and entering a using block
|
||||
* Main entwine function. Used for new definitions, calling into a namespace (or forcing the base namespace) and entering a using block
|
||||
*
|
||||
*/
|
||||
concrete: function(spacename) {
|
||||
entwine: function(spacename) {
|
||||
var i = 0;
|
||||
var selector = this.selector ? $.selector(this.selector) : null;
|
||||
/* Don't actually work out selector until we try and define something on it - we might be opening a namespace on an function-traveresed object
|
||||
which have non-standard selectors like .parents(.foo).slice(0,1) */
|
||||
var selector = null;
|
||||
|
||||
/* By default we operator on the base namespace */
|
||||
var namespace = namespaces.__base || $.concrete.Namespace();
|
||||
var namespace = namespaces.__base || $.entwine.Namespace();
|
||||
|
||||
/* If the first argument is a string, then it's the name of a namespace. Look it up */
|
||||
if (typeof spacename == 'string') {
|
||||
if (spacename.charAt('0') == '.') spacename = spacename.substr(1);
|
||||
if (spacename) namespace = namespaces[spacename] || $.concrete.Namespace(spacename);
|
||||
if (spacename) namespace = namespaces[spacename] || $.entwine.Namespace(spacename);
|
||||
i=1;
|
||||
}
|
||||
|
||||
@ -298,19 +317,19 @@ var console;
|
||||
while (i < arguments.length) {
|
||||
var res = arguments[i++];
|
||||
|
||||
// If it's a function, call it - either it's a using block or it's a namespaced concrete definition
|
||||
// If it's a function, call it - either it's a using block or it's a namespaced entwine definition
|
||||
if ($.isFunction(res)) {
|
||||
if (res.length != 1) $.concrete.warn('Function block inside concrete definition does not take $ argument properly', $.concrete.WARN_LEVEL_IMPORTANT);
|
||||
if (res.length != 1) $.entwine.warn('Function block inside entwine definition does not take $ argument properly', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
res = res.call(namespace.$(this), namespace.$);
|
||||
}
|
||||
|
||||
// If we have a concrete definition hash, inject it into namespace
|
||||
// If we have a entwine definition hash, inject it into namespace
|
||||
if (res) {
|
||||
if (selector === null) selector = this.selector ? $.selector(this.selector) : false;
|
||||
|
||||
if (selector) namespace.add(selector, res);
|
||||
else $.concrete.warn('Concrete block given to concrete call without selector. Make sure you call $(selector).concrete when defining blocks', $.concrete.WARN_LEVEL_IMPORTANT);
|
||||
else $.entwine.warn('Entwine block given to entwine call without selector. Make sure you call $(selector).entwine when defining blocks', $.entwine.WARN_LEVEL_IMPORTANT);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Finally, return the jQuery object 'this' refers to, wrapped in the new namespace */
|
||||
@ -318,7 +337,7 @@ var console;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls the next most specific version of the current concrete method
|
||||
* Calls the next most specific version of the current entwine method
|
||||
*/
|
||||
_super: function(){
|
||||
var rv, i = this.length;
|
21
thirdparty/jquery-entwine/src/jquery.entwine.legacy.js
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
(function($) {
|
||||
|
||||
// Adds back concrete methods for backwards compatibility
|
||||
$.concrete = $.entwine;
|
||||
$.fn.concrete = $.fn.entwine;
|
||||
$.fn.concreteData = $.fn.entwineData;
|
||||
|
||||
// Use addHandler to hack in the namespace.$.concrete equivilent to the namespace.$.entwine namespace-injection
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 100,
|
||||
bind: function(selector, k, v) { return false; },
|
||||
|
||||
namespaceMethodOverrides: function(namespace){
|
||||
namespace.$.concrete = namespace.$.entwine;
|
||||
namespace.injectee.concrete = namespace.injectee.entwine;
|
||||
namespace.injectee.concreteData = namespace.injectee.entwineData;
|
||||
return {};
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
85
thirdparty/jquery-entwine/src/jquery.entwine.properties.js
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
(function($) {
|
||||
|
||||
var entwine_prepend = '__entwine!';
|
||||
|
||||
var getEntwineData = function(el, namespace, property) {
|
||||
return el.data(entwine_prepend + namespace + '!' + property);
|
||||
};
|
||||
|
||||
var setEntwineData = function(el, namespace, property, value) {
|
||||
return el.data(entwine_prepend + namespace + '!' + property, value);
|
||||
};
|
||||
|
||||
var getEntwineDataAsHash = function(el, namespace) {
|
||||
var hash = {};
|
||||
var id = jQuery.data(el[0]);
|
||||
|
||||
var matchstr = entwine_prepend + namespace + '!';
|
||||
var matchlen = matchstr.length;
|
||||
|
||||
var cache = jQuery.cache[id];
|
||||
for (var k in cache) {
|
||||
if (k.substr(0,matchlen) == matchstr) hash[k.substr(matchlen)] = cache[k];
|
||||
}
|
||||
|
||||
return hash;
|
||||
};
|
||||
|
||||
var setEntwineDataFromHash = function(el, namespace, hash) {
|
||||
for (var k in hash) setEntwineData(namespace, k, hash[k]);
|
||||
};
|
||||
|
||||
var entwineData = function(el, namespace, args) {
|
||||
switch (args.length) {
|
||||
case 0:
|
||||
return getEntwineDataAsHash(el, namespace);
|
||||
case 1:
|
||||
if (typeof args[0] == 'string') return getEntwineData(el, namespace, args[0]);
|
||||
else return setEntwineDataFromHash(el, namespace, args[0]);
|
||||
default:
|
||||
return setEntwineData(el, namespace, args[0], args[1]);
|
||||
}
|
||||
};
|
||||
|
||||
$.extend($.fn, {
|
||||
entwineData: function() {
|
||||
return entwineData(this, '__base', arguments);
|
||||
}
|
||||
});
|
||||
|
||||
$.entwine.Namespace.addHandler({
|
||||
order: 60,
|
||||
|
||||
bind: function(selector, k, v) {
|
||||
if (k.charAt(0) != k.charAt(0).toUpperCase()) $.entwine.warn('Entwine property '+k+' does not start with a capital letter', $.entwine.WARN_LEVEL_BESTPRACTISE);
|
||||
|
||||
// Create the getters and setters
|
||||
|
||||
var getterName = 'get'+k;
|
||||
var setterName = 'set'+k;
|
||||
|
||||
this.bind_proxy(selector, getterName, function() { return this.entwineData(k) || v ; });
|
||||
this.bind_proxy(selector, setterName, function(v){ return this.entwineData(k, v); });
|
||||
|
||||
// Get the get and set proxies we just created
|
||||
|
||||
var getter = this.injectee[getterName];
|
||||
var setter = this.injectee[setterName];
|
||||
|
||||
// And bind in the jQuery-style accessor
|
||||
|
||||
this.bind_proxy(selector, k, function(v){ return (arguments.length == 1 ? setter : getter).call(this, v) ; });
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
namespaceMethodOverrides: function(namespace){
|
||||
return {
|
||||
entwineData: function() {
|
||||
return entwineData(this, namespace.name, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 457 B |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 499 B After Width: | Height: | Size: 499 B |
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 524 B |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 64 B After Width: | Height: | Size: 64 B |
Before Width: | Height: | Size: 300 B After Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 202 B After Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 516 B |
@ -12,17 +12,18 @@ var Base;
|
||||
|
||||
(function(){
|
||||
|
||||
var marker = {}, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
var marker = {}, fnTest = /xyz/.test(function(){var xyz;}) ? /\b_super\b/ : /.*/;
|
||||
|
||||
// The base Class implementation (does nothing)
|
||||
Base = function(){};
|
||||
|
||||
Base.addMethod = function(name, func) {
|
||||
var _super = this._super;
|
||||
if (_super && fnTest.test(func)) {
|
||||
var parent = this._super && this._super.prototype;
|
||||
|
||||
if (parent && fnTest.test(func)) {
|
||||
this.prototype[name] = function(){
|
||||
var tmp = this._super;
|
||||
this._super = _super[name];
|
||||
this._super = parent[name];
|
||||
try {
|
||||
var ret = func.apply(this, arguments);
|
||||
}
|
||||
@ -30,17 +31,25 @@ var Base;
|
||||
this._super = tmp;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
}
|
||||
else this.prototype[name] = func;
|
||||
}
|
||||
};
|
||||
|
||||
Base.addMethods = function(props) {
|
||||
for (var name in props) {
|
||||
if (typeof props[name] == 'function') this.addMethod(name, props[name]);
|
||||
else this.prototype[name] = props[name];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Base.subclassOf = function(parentkls) {
|
||||
var kls = this;
|
||||
while (kls) {
|
||||
if (kls === parentkls) return true;
|
||||
kls = kls._super;
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
Base.extend = function(props) {
|
||||
@ -55,18 +64,21 @@ var Base;
|
||||
else {
|
||||
var ret = new Kls(marker); if (ret.init) ret.init.apply(ret, arguments); return ret;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Add the common class variables and methods
|
||||
Kls.constructor = Kls;
|
||||
Kls.extend = Base.extend;
|
||||
Kls.addMethod = Base.addMethod;
|
||||
Kls.addMethods = Base.addMethods;
|
||||
Kls._super = this.prototype;
|
||||
Kls.subclassOf = Base.subclassOf;
|
||||
|
||||
Kls._super = this;
|
||||
|
||||
// Attach the parent object to the inheritance chain
|
||||
Kls.prototype = new this(marker);
|
||||
|
||||
Kls.prototype.constructor = Kls;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
Kls.addMethods(props);
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
WITHN: /([-+])?(INTEGER)?(n)\s*(?:([-+])\s*(INTEGER))?/,
|
||||
WITHOUTN: /([-+])?(INTEGER)/
|
||||
}
|
||||
};
|
||||
|
||||
var rx = {
|
||||
not: /:not\(/,
|
||||
@ -38,12 +38,12 @@
|
||||
comb: /\s*(\+|~|>)\s*|\s+/,
|
||||
comma: /\s*,\s*/,
|
||||
important: /\s+!important\s*$/
|
||||
}
|
||||
};
|
||||
|
||||
/* Replace placeholders with actual regex, and mark all as case insensitive */
|
||||
var token = /[A-Z][A-Z0-9]+/;
|
||||
for (var k in rx) {
|
||||
var src = rx[k].source;
|
||||
var m, src = rx[k].source;
|
||||
while (m = src.match(token)) src = src.replace(m[0], tokens[m[0]].source);
|
||||
rx[k] = new RegExp(src, 'gi');
|
||||
}
|
||||
@ -77,7 +77,7 @@
|
||||
done: function() {
|
||||
return this.pos == this.str.length;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
/* A base class that all Selectors inherit off */
|
||||
var SelectorBase = Base.extend({});
|
||||
@ -104,7 +104,7 @@
|
||||
/* Then for each selection type, try and find a match */
|
||||
do {
|
||||
if (m = selector.match(rx.not)) {
|
||||
this.nots[this.nots.length] = SelectorsGroup().parse(selector)
|
||||
this.nots[this.nots.length] = SelectorsGroup().parse(selector);
|
||||
if (!(m = selector.match(rx.not_end))) {
|
||||
throw 'Invalid :not term in selector';
|
||||
}
|
||||
@ -130,7 +130,7 @@
|
||||
|
||||
return this;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* A class representing a Selector, as per the CSS3 selector spec
|
||||
@ -178,11 +178,11 @@
|
||||
|
||||
if (!cons.done()) throw 'Could not parse selector - ' + cons.showpos() ;
|
||||
else return res;
|
||||
}
|
||||
};
|
||||
|
||||
$.selector.SelectorBase = SelectorBase;
|
||||
$.selector.SimpleSelector = SimpleSelector;
|
||||
$.selector.Selector = Selector;
|
||||
$.selector.SelectorsGroup = SelectorsGroup;
|
||||
|
||||
})(jQuery)
|
||||
})(jQuery);
|
@ -18,16 +18,16 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
// Does browser support Element.children
|
||||
var hasChildren = div.children && div.children[0].tagName == 'FORM';
|
||||
|
||||
var FUNC_IN = /^\s*function\s*\([^)]*\)\s*{/;
|
||||
var FUNC_IN = /^\s*function\s*\([^)]*\)\s*\{/;
|
||||
var FUNC_OUT = /}\s*$/;
|
||||
|
||||
var funcToString = function(f) {
|
||||
return (''+f).replace(FUNC_IN,'').replace(FUNC_OUT,'');
|
||||
}
|
||||
};
|
||||
|
||||
// Can we use Function#toString ?
|
||||
try {
|
||||
var testFunc = function(){ return 'good' };
|
||||
var testFunc = function(){ return 'good'; };
|
||||
if ((new Function('',funcToString(testFunc)))() != 'good') funcToString = false;
|
||||
}
|
||||
catch(e) { funcToString = false; console.log(e.message);/*pass*/ }
|
||||
@ -41,21 +41,26 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
|
||||
var join = function(js) {
|
||||
return js.join('\n');
|
||||
}
|
||||
};
|
||||
|
||||
var join_complex = function(js) {
|
||||
code = new String(js.join('\n')); // String objects can have properties set. strings can't
|
||||
var code = new String(js.join('\n')); // String objects can have properties set. strings can't
|
||||
code.complex = true;
|
||||
return code;
|
||||
}
|
||||
};
|
||||
|
||||
/**** ATTRIBUTE ACCESSORS ****/
|
||||
|
||||
// Not all attribute names can be used as identifiers, so we encode any non-acceptable characters as hex
|
||||
var varForAttr = function(attr) {
|
||||
return '_' + attr.replace(/^[^A-Za-z]|[^A-Za-z0-9]/g, function(m){ return '_0x' + m.charCodeAt(0).toString(16) + '_'; });
|
||||
};
|
||||
|
||||
var getAttr;
|
||||
|
||||
// Good browsers
|
||||
if (!getAttributeDodgy) {
|
||||
getAttr = function(attr){ return 'var _'+attr+' = el.getAttribute("'+attr+'");' ; }
|
||||
getAttr = function(attr){ return 'var '+varForAttr(attr)+' = el.getAttribute("'+attr+'");' ; };
|
||||
}
|
||||
// IE 6, 7
|
||||
else {
|
||||
@ -64,21 +69,21 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
|
||||
getAttr = function(attr) {
|
||||
var ieattr = getAttrIEMap[attr] || attr;
|
||||
return 'var _'+attr+' = el.getAttribute("'+ieattr+'",2) || (el.getAttributeNode("'+attr+'")||{}).nodeValue;';
|
||||
}
|
||||
return 'var '+varForAttr(attr)+' = el.getAttribute("'+ieattr+'",2) || (el.getAttributeNode("'+attr+'")||{}).nodeValue;';
|
||||
};
|
||||
}
|
||||
|
||||
/**** ATTRIBUTE COMPARITORS ****/
|
||||
|
||||
var attrchecks = {
|
||||
'-': '!_K',
|
||||
'=': '_K != "V"',
|
||||
'!=': '_K == "V"',
|
||||
'~=': '__K.indexOf(" V ") == -1',
|
||||
'^=': '!_K || _K.indexOf("V") != 0',
|
||||
'*=': '!_K || _K.indexOf("V") == -1',
|
||||
'$=': '!_K || _K.substr(_K.length-"V".length) != "V"'
|
||||
}
|
||||
'-': '!K',
|
||||
'=': 'K != "V"',
|
||||
'!=': 'K == "V"',
|
||||
'~=': '_WS_K.indexOf(" V ") == -1',
|
||||
'^=': '!K || K.indexOf("V") != 0',
|
||||
'*=': '!K || K.indexOf("V") == -1',
|
||||
'$=': '!K || K.substr(K.length-"V".length) != "V"'
|
||||
};
|
||||
|
||||
/**** STATE TRACKER ****/
|
||||
|
||||
@ -106,7 +111,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
return join([
|
||||
'while(el = el.previousSibling){',
|
||||
'if (el.nodeType != 1) continue;',
|
||||
body,
|
||||
body
|
||||
]);
|
||||
},
|
||||
parent: function() {
|
||||
@ -130,7 +135,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
uses_wsattr: function(attr) {
|
||||
if (this.wsattrs[attr]) return;
|
||||
this.wsattrs[attr] = true;
|
||||
return join([this.uses_attr(attr), 'var __'+attr+' = " "+_'+attr+'+" ";']);
|
||||
return join([this.uses_attr(attr), 'var _WS_'+varForAttr(attr)+' = " "+'+varForAttr(attr)+'+" ";']);
|
||||
},
|
||||
|
||||
save: function(lbl) {
|
||||
@ -147,7 +152,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
var pseudoclschecks = {
|
||||
'first-child': join([
|
||||
'var cel = el;',
|
||||
'while(cel = cel.previousSibling){ if (cel.nodeType === 1) BAD; }',
|
||||
'while(cel = cel.previousSibling){ if (cel.nodeType === 1) BAD; }'
|
||||
]),
|
||||
'last-child': join([
|
||||
'var cel = el;',
|
||||
@ -158,7 +163,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
'var i = 1, cel = el;',
|
||||
'while(cel = cel.previousSibling){',
|
||||
'if (cel.nodeType === 1) i++;',
|
||||
'}',
|
||||
'}'
|
||||
]);
|
||||
|
||||
if (a == 0) return join([
|
||||
@ -207,15 +212,15 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
|
||||
/* Check against class names */
|
||||
$.each(this.classes, function(i, cls){
|
||||
js[js.length] = 'if (__class.indexOf(" '+cls+' ") == -1) BAD;';
|
||||
})
|
||||
js[js.length] = 'if (_WS__class.indexOf(" '+cls+' ") == -1) BAD;';
|
||||
});
|
||||
}
|
||||
|
||||
/* Check against attributes */
|
||||
$.each(this.attrs, function(i, attr){
|
||||
js[js.length] = (attr[1] == '~=') ? el.uses_wsattr(attr[0]) : el.uses_attr(attr[0]);
|
||||
var check = attrchecks[ attr[1] || '-' ];
|
||||
check = check.replace( /K/g, attr[0]).replace( /V/g, attr[2] && attr[2].match(STARTS_WITH_QUOTES) ? attr[2].slice(1,-1) : attr[2] );
|
||||
check = check.replace( /K/g, varForAttr(attr[0])).replace( /V/g, attr[2] && attr[2].match(STARTS_WITH_QUOTES) ? attr[2].slice(1,-1) : attr[2] );
|
||||
js[js.length] = 'if ('+check+') BAD;';
|
||||
});
|
||||
|
||||
@ -232,7 +237,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
el.save(lbl),
|
||||
func,
|
||||
el.restore(lbl)
|
||||
])
|
||||
]);
|
||||
|
||||
js[js.length] = func;
|
||||
});
|
||||
@ -248,7 +253,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
js[js.length] = funcToString(check).replace(/elem/g,'el').replace(/return([^;]+);/,'if (!($1)) BAD;');
|
||||
}
|
||||
else {
|
||||
js[js.length] = 'if (!$.find.selectors.filters.'+pscls[0]+'(el)) BAD;'
|
||||
js[js.length] = 'if (!$.find.selectors.filters.'+pscls[0]+'(el)) BAD;';
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -266,7 +271,7 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
return join([
|
||||
'l'+(++lbl_id)+':{',
|
||||
f.replace(GOOD, 'break l'+lbl_id),
|
||||
'}',
|
||||
'}'
|
||||
]);
|
||||
else
|
||||
return f.replace(GOOD, '');
|
||||
@ -314,11 +319,11 @@ Sizzle is good for finding elements for a selector, but not so good for telling
|
||||
};
|
||||
|
||||
$.selector.Selector.addMethod('compile', function(el) {
|
||||
l = this.parts.length;
|
||||
var l = this.parts.length;
|
||||
|
||||
expr = this.parts[--l].compile(el);
|
||||
var expr = this.parts[--l].compile(el);
|
||||
while (l) {
|
||||
combinator = this.parts[--l];
|
||||
var combinator = this.parts[--l];
|
||||
expr = combines[combinator](el, this.parts[--l], as_subexpr(expr));
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
})
|
||||
});
|
||||
|
||||
$.selector.Selector.addMethod('specifity', function(){
|
||||
if (this.spec) return this.spec;
|
||||
@ -25,7 +25,7 @@
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
})
|
||||
});
|
||||
|
||||
$.selector.SelectorsGroup.addMethod('specifity', function(){
|
||||
if (this.spec) return this.spec;
|
||||
@ -36,7 +36,7 @@
|
||||
});
|
||||
|
||||
return this.spec = spec;
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
})(jQuery);
|
Before Width: | Height: | Size: 154 B After Width: | Height: | Size: 154 B |
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 145 B |