jquery-entwine-rails 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +12 -0
- data/Rakefile +1 -0
- data/jquery-entwine-rails.gemspec +22 -0
- data/lib/jquery-entwine-rails.rb +9 -0
- data/lib/jquery-entwine-rails/engine.rb +9 -0
- data/lib/jquery-entwine-rails/version.rb +7 -0
- data/vendor/assets/javascripts/jquery.entwine.js +1675 -0
- metadata +66 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "jquery-entwine-rails/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "jquery-entwine-rails"
|
|
7
|
+
s.version = Jquery::Entwine::Rails::VERSION
|
|
8
|
+
s.authors = ["The FrontSide"]
|
|
9
|
+
s.email = ["info@thefrontside.net"]
|
|
10
|
+
s.homepage = ""
|
|
11
|
+
s.summary = %q{Use the jquery-entwine plugin within Rails}
|
|
12
|
+
s.description = %q{Uses the Rails 3.1 Asset Pipeline to bring in the jquery-entwine library}
|
|
13
|
+
|
|
14
|
+
s.rubyforge_project = "jquery-entwine-rails"
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_paths = ["lib", "vendor"]
|
|
20
|
+
|
|
21
|
+
s.add_runtime_dependency "jquery-rails"
|
|
22
|
+
end
|
|
@@ -0,0 +1,1675 @@
|
|
|
1
|
+
//= require jquery
|
|
2
|
+
/* jQuery.Entwine - Copyright 2009-2011 Hamish Friedlander and SilverStripe. Version . */
|
|
3
|
+
|
|
4
|
+
/* vendor/jquery.selector/jquery.class.js */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Very basic Class utility. Based on base and jquery.class.
|
|
8
|
+
*
|
|
9
|
+
* Class definition: var Foo = Base.extend({ init: function(){ Constructor }; method_name: function(){ Method } });
|
|
10
|
+
*
|
|
11
|
+
* Inheritance: var Bar = Foo.extend({ method_name: function(){ this._super(); } });
|
|
12
|
+
*
|
|
13
|
+
* new-less Constructor: new Foo(arg) <-same as-> Foo(arg)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
var Base;
|
|
17
|
+
|
|
18
|
+
(function(){
|
|
19
|
+
|
|
20
|
+
var marker = {}, fnTest = /xyz/.test(function(){var xyz;}) ? /\b_super\b/ : /.*/;
|
|
21
|
+
|
|
22
|
+
// The base Class implementation (does nothing)
|
|
23
|
+
Base = function(){};
|
|
24
|
+
|
|
25
|
+
Base.addMethod = function(name, func) {
|
|
26
|
+
var parent = this._super && this._super.prototype;
|
|
27
|
+
|
|
28
|
+
if (parent && fnTest.test(func)) {
|
|
29
|
+
this.prototype[name] = function(){
|
|
30
|
+
var tmp = this._super;
|
|
31
|
+
this._super = parent[name];
|
|
32
|
+
try {
|
|
33
|
+
var ret = func.apply(this, arguments);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
this._super = tmp;
|
|
37
|
+
}
|
|
38
|
+
return ret;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
else this.prototype[name] = func;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
Base.addMethods = function(props) {
|
|
45
|
+
for (var name in props) {
|
|
46
|
+
if (typeof props[name] == 'function') this.addMethod(name, props[name]);
|
|
47
|
+
else this.prototype[name] = props[name];
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
Base.subclassOf = function(parentkls) {
|
|
52
|
+
var kls = this;
|
|
53
|
+
while (kls) {
|
|
54
|
+
if (kls === parentkls) return true;
|
|
55
|
+
kls = kls._super;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// Create a new Class that inherits from this class
|
|
60
|
+
Base.extend = function(props) {
|
|
61
|
+
|
|
62
|
+
// The dummy class constructor
|
|
63
|
+
var Kls = function() {
|
|
64
|
+
if (arguments[0] === marker) return;
|
|
65
|
+
|
|
66
|
+
if (this instanceof Kls) {
|
|
67
|
+
if (this.init) this.init.apply(this, arguments);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
var ret = new Kls(marker); if (ret.init) ret.init.apply(ret, arguments); return ret;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Add the common class variables and methods
|
|
75
|
+
Kls.constructor = Kls;
|
|
76
|
+
Kls.extend = Base.extend;
|
|
77
|
+
Kls.addMethod = Base.addMethod;
|
|
78
|
+
Kls.addMethods = Base.addMethods;
|
|
79
|
+
Kls.subclassOf = Base.subclassOf;
|
|
80
|
+
|
|
81
|
+
Kls._super = this;
|
|
82
|
+
|
|
83
|
+
// Attach the parent object to the inheritance chain
|
|
84
|
+
Kls.prototype = new this(marker);
|
|
85
|
+
Kls.prototype.constructor = Kls;
|
|
86
|
+
|
|
87
|
+
// Copy the properties over onto the new prototype
|
|
88
|
+
Kls.addMethods(props);
|
|
89
|
+
|
|
90
|
+
return Kls;
|
|
91
|
+
};
|
|
92
|
+
})();;
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
/* vendor/jquery.selector/jquery.selector.js */
|
|
96
|
+
|
|
97
|
+
(function($){
|
|
98
|
+
|
|
99
|
+
var tokens = {
|
|
100
|
+
UNICODE: /\\[0-9a-f]{1,6}(?:\r\n|[ \n\r\t\f])?/,
|
|
101
|
+
ESCAPE: /(?:UNICODE)|\\[^\n\r\f0-9a-f]/,
|
|
102
|
+
NONASCII: /[^\x00-\x7F]/,
|
|
103
|
+
NMSTART: /[_a-z]|(?:NONASCII)|(?:ESCAPE)/,
|
|
104
|
+
NMCHAR: /[_a-z0-9-]|(?:NONASCII)|(?:ESCAPE)/,
|
|
105
|
+
IDENT: /-?(?:NMSTART)(?:NMCHAR)*/,
|
|
106
|
+
|
|
107
|
+
NL: /\n|\r\n|\r|\f/,
|
|
108
|
+
|
|
109
|
+
STRING: /(?:STRING1)|(?:STRING2)|(?:STRINGBARE)/,
|
|
110
|
+
STRING1: /"(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\"])*"/,
|
|
111
|
+
STRING2: /'(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\'])*'/,
|
|
112
|
+
STRINGBARE: /(?:(?:ESCAPE)|\\(?:NL)|[^\n\r\f\]])*/,
|
|
113
|
+
|
|
114
|
+
FUNCTION: /(?:IDENT)\(\)/,
|
|
115
|
+
|
|
116
|
+
INTEGER: /[0-9]+/,
|
|
117
|
+
|
|
118
|
+
WITHN: /([-+])?(INTEGER)?(n)\s*(?:([-+])\s*(INTEGER))?/,
|
|
119
|
+
WITHOUTN: /([-+])?(INTEGER)/
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
var rx = {
|
|
123
|
+
not: /:not\(/,
|
|
124
|
+
not_end: /\)/,
|
|
125
|
+
|
|
126
|
+
tag: /((?:IDENT)|\*)/,
|
|
127
|
+
id: /#(IDENT)/,
|
|
128
|
+
cls: /\.(IDENT)/,
|
|
129
|
+
attr: /\[\s*(IDENT)\s*(?:([^=]?=)\s*(STRING)\s*)?\]/,
|
|
130
|
+
pseudo_el: /(?::(first-line|first-letter|before|after))|(?:::((?:FUNCTION)|(?:IDENT)))/,
|
|
131
|
+
pseudo_cls_nth: /:nth-child\(\s*(?:(?:WITHN)|(?:WITHOUTN)|(odd|even))\s*\)/,
|
|
132
|
+
pseudo_cls: /:(IDENT)/,
|
|
133
|
+
|
|
134
|
+
comb: /\s*(\+|~|>)\s*|\s+/,
|
|
135
|
+
comma: /\s*,\s*/,
|
|
136
|
+
important: /\s+!important\s*$/
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/* Replace placeholders with actual regex, and mark all as case insensitive */
|
|
140
|
+
var token = /[A-Z][A-Z0-9]+/;
|
|
141
|
+
for (var k in rx) {
|
|
142
|
+
var m, src = rx[k].source;
|
|
143
|
+
while (m = src.match(token)) src = src.replace(m[0], tokens[m[0]].source);
|
|
144
|
+
rx[k] = new RegExp(src, 'gi');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* A string that matches itself against regexii, and keeps track of how much of itself has been matched
|
|
149
|
+
*/
|
|
150
|
+
var ConsumableString = Base.extend({
|
|
151
|
+
init: function(str) {
|
|
152
|
+
this.str = str;
|
|
153
|
+
this.pos = 0;
|
|
154
|
+
},
|
|
155
|
+
match: function(rx) {
|
|
156
|
+
var m;
|
|
157
|
+
rx.lastIndex = this.pos;
|
|
158
|
+
if ((m = rx.exec(this.str)) && m.index == this.pos ) {
|
|
159
|
+
this.pos = rx.lastIndex ? rx.lastIndex : this.str.length ;
|
|
160
|
+
return m;
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
},
|
|
164
|
+
peek: function(rx) {
|
|
165
|
+
var m;
|
|
166
|
+
rx.lastIndex = this.pos;
|
|
167
|
+
if ((m = rx.exec(this.str)) && m.index == this.pos ) return m;
|
|
168
|
+
return null;
|
|
169
|
+
},
|
|
170
|
+
showpos: function() {
|
|
171
|
+
return this.str.slice(0,this.pos)+'<HERE>' + this.str.slice(this.pos);
|
|
172
|
+
},
|
|
173
|
+
done: function() {
|
|
174
|
+
return this.pos == this.str.length;
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/* A base class that all Selectors inherit off */
|
|
179
|
+
var SelectorBase = Base.extend({});
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* A class representing a Simple Selector, as per the CSS3 selector spec
|
|
183
|
+
*/
|
|
184
|
+
var SimpleSelector = SelectorBase.extend({
|
|
185
|
+
init: function() {
|
|
186
|
+
this.tag = null;
|
|
187
|
+
this.id = null;
|
|
188
|
+
this.classes = [];
|
|
189
|
+
this.attrs = [];
|
|
190
|
+
this.nots = [];
|
|
191
|
+
this.pseudo_classes = [];
|
|
192
|
+
this.pseudo_els = [];
|
|
193
|
+
},
|
|
194
|
+
parse: function(selector) {
|
|
195
|
+
var m;
|
|
196
|
+
|
|
197
|
+
/* Pull out the initial tag first, if there is one */
|
|
198
|
+
if (m = selector.match(rx.tag)) this.tag = m[1];
|
|
199
|
+
|
|
200
|
+
/* Then for each selection type, try and find a match */
|
|
201
|
+
do {
|
|
202
|
+
if (m = selector.match(rx.not)) {
|
|
203
|
+
this.nots[this.nots.length] = SelectorsGroup().parse(selector);
|
|
204
|
+
if (!(m = selector.match(rx.not_end))) {
|
|
205
|
+
throw 'Invalid :not term in selector';
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if (m = selector.match(rx.id)) this.id = m[1];
|
|
209
|
+
else if (m = selector.match(rx.cls)) this.classes[this.classes.length] = m[1];
|
|
210
|
+
else if (m = selector.match(rx.attr)) this.attrs[this.attrs.length] = [ m[1], m[2], m[3] ];
|
|
211
|
+
else if (m = selector.match(rx.pseudo_el)) this.pseudo_els[this.pseudo_els.length] = m[1] || m[2];
|
|
212
|
+
else if (m = selector.match(rx.pseudo_cls_nth)) {
|
|
213
|
+
if (m[3]) {
|
|
214
|
+
var a = parseInt((m[1]||'')+(m[2]||'1'));
|
|
215
|
+
var b = parseInt((m[4]||'')+(m[5]||'0'));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
var a = m[8] ? 2 : 0;
|
|
219
|
+
var b = m[8] ? (4-m[8].length) : parseInt((m[6]||'')+m[7]);
|
|
220
|
+
}
|
|
221
|
+
this.pseudo_classes[this.pseudo_classes.length] = ['nth-child', [a, b]];
|
|
222
|
+
}
|
|
223
|
+
else if (m = selector.match(rx.pseudo_cls)) this.pseudo_classes[this.pseudo_classes.length] = [m[1]];
|
|
224
|
+
|
|
225
|
+
} while(m && !selector.done());
|
|
226
|
+
|
|
227
|
+
return this;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* A class representing a Selector, as per the CSS3 selector spec
|
|
233
|
+
*/
|
|
234
|
+
var Selector = SelectorBase.extend({
|
|
235
|
+
init: function(){
|
|
236
|
+
this.parts = [];
|
|
237
|
+
},
|
|
238
|
+
parse: function(cons){
|
|
239
|
+
this.parts[this.parts.length] = SimpleSelector().parse(cons);
|
|
240
|
+
|
|
241
|
+
while (!cons.done() && !cons.peek(rx.comma) && (m = cons.match(rx.comb))) {
|
|
242
|
+
this.parts[this.parts.length] = m[1] || ' ';
|
|
243
|
+
this.parts[this.parts.length] = SimpleSelector().parse(cons);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return this.parts.length == 1 ? this.parts[0] : this;
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* A class representing a sequence of selectors, as per the CSS3 selector spec
|
|
252
|
+
*/
|
|
253
|
+
var SelectorsGroup = SelectorBase.extend({
|
|
254
|
+
init: function(){
|
|
255
|
+
this.parts = [];
|
|
256
|
+
},
|
|
257
|
+
parse: function(cons){
|
|
258
|
+
this.parts[this.parts.length] = Selector().parse(cons);
|
|
259
|
+
|
|
260
|
+
while (!cons.done() && (m = cons.match(rx.comma))) {
|
|
261
|
+
this.parts[this.parts.length] = Selector().parse(cons);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return this.parts.length == 1 ? this.parts[0] : this;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
$.selector = function(s){
|
|
270
|
+
var cons = ConsumableString(s);
|
|
271
|
+
var res = SelectorsGroup().parse(cons);
|
|
272
|
+
|
|
273
|
+
res.selector = s;
|
|
274
|
+
|
|
275
|
+
if (!cons.done()) throw 'Could not parse selector - ' + cons.showpos() ;
|
|
276
|
+
else return res;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
$.selector.SelectorBase = SelectorBase;
|
|
280
|
+
$.selector.SimpleSelector = SimpleSelector;
|
|
281
|
+
$.selector.Selector = Selector;
|
|
282
|
+
$.selector.SelectorsGroup = SelectorsGroup;
|
|
283
|
+
|
|
284
|
+
})(jQuery);
|
|
285
|
+
;
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
/* vendor/jquery.selector/jquery.selector.specifity.js */
|
|
289
|
+
|
|
290
|
+
(function($) {
|
|
291
|
+
|
|
292
|
+
$.selector.SimpleSelector.addMethod('specifity', function() {
|
|
293
|
+
if (this.spec) return this.spec;
|
|
294
|
+
|
|
295
|
+
var spec = [
|
|
296
|
+
this.id ? 1 : 0,
|
|
297
|
+
this.classes.length + this.attrs.length + this.pseudo_classes.length,
|
|
298
|
+
((this.tag && this.tag != '*') ? 1 : 0) + this.pseudo_els.length
|
|
299
|
+
];
|
|
300
|
+
$.each(this.nots, function(i,not){
|
|
301
|
+
var ns = not.specifity(); spec[0] += ns[0]; spec[1] += ns[1]; spec[2] += ns[2];
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
return this.spec = spec;
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
$.selector.Selector.addMethod('specifity', function(){
|
|
308
|
+
if (this.spec) return this.spec;
|
|
309
|
+
|
|
310
|
+
var spec = [0,0,0];
|
|
311
|
+
$.each(this.parts, function(i,part){
|
|
312
|
+
if (i%2) return;
|
|
313
|
+
var ps = part.specifity(); spec[0] += ps[0]; spec[1] += ps[1]; spec[2] += ps[2];
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
return this.spec = spec;
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
$.selector.SelectorsGroup.addMethod('specifity', function(){
|
|
320
|
+
if (this.spec) return this.spec;
|
|
321
|
+
|
|
322
|
+
var spec = [0,0,0];
|
|
323
|
+
$.each(this.parts, function(i,part){
|
|
324
|
+
var ps = part.specifity(); spec[0] += ps[0]; spec[1] += ps[1]; spec[2] += ps[2];
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return this.spec = spec;
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
})(jQuery);
|
|
332
|
+
;
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
/* vendor/jquery.selector/jquery.selector.matches.js */
|
|
336
|
+
|
|
337
|
+
/*
|
|
338
|
+
This attempts to do the opposite of Sizzle.
|
|
339
|
+
Sizzle is good for finding elements for a selector, but not so good for telling if an individual element matches a selector
|
|
340
|
+
*/
|
|
341
|
+
|
|
342
|
+
(function($) {
|
|
343
|
+
|
|
344
|
+
/**** CAPABILITY TESTS ****/
|
|
345
|
+
var div = document.createElement('div');
|
|
346
|
+
div.innerHTML = '<form id="test"><input name="id" type="text"/></form>';
|
|
347
|
+
|
|
348
|
+
// In IE 6-7, getAttribute often does the wrong thing (returns similar to el.attr), so we need to use getAttributeNode on that browser
|
|
349
|
+
var getAttributeDodgy = div.firstChild.getAttribute('id') !== 'test';
|
|
350
|
+
|
|
351
|
+
// Does browser support Element.firstElementChild, Element.previousElementSibling, etc.
|
|
352
|
+
var hasElementTraversal = div.firstElementChild && div.firstElementChild.tagName == 'FORM';
|
|
353
|
+
|
|
354
|
+
// Does browser support Element.children
|
|
355
|
+
var hasChildren = div.children && div.children[0].tagName == 'FORM';
|
|
356
|
+
|
|
357
|
+
var FUNC_IN = /^\s*function\s*\([^)]*\)\s*\{/;
|
|
358
|
+
var FUNC_OUT = /}\s*$/;
|
|
359
|
+
|
|
360
|
+
var funcToString = function(f) {
|
|
361
|
+
return (''+f).replace(FUNC_IN,'').replace(FUNC_OUT,'');
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
// Can we use Function#toString ?
|
|
365
|
+
try {
|
|
366
|
+
var testFunc = function(){ return 'good'; };
|
|
367
|
+
if ((new Function('',funcToString(testFunc)))() != 'good') funcToString = false;
|
|
368
|
+
}
|
|
369
|
+
catch(e) { funcToString = false; console.log(e.message);/*pass*/ }
|
|
370
|
+
|
|
371
|
+
/**** INTRO ****/
|
|
372
|
+
|
|
373
|
+
var GOOD = /GOOD/g;
|
|
374
|
+
var BAD = /BAD/g;
|
|
375
|
+
|
|
376
|
+
var STARTS_WITH_QUOTES = /^['"]/g;
|
|
377
|
+
|
|
378
|
+
var join = function(js) {
|
|
379
|
+
return js.join('\n');
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
var join_complex = function(js) {
|
|
383
|
+
var code = new String(js.join('\n')); // String objects can have properties set. strings can't
|
|
384
|
+
code.complex = true;
|
|
385
|
+
return code;
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
/**** ATTRIBUTE ACCESSORS ****/
|
|
389
|
+
|
|
390
|
+
// Not all attribute names can be used as identifiers, so we encode any non-acceptable characters as hex
|
|
391
|
+
var varForAttr = function(attr) {
|
|
392
|
+
return '_' + attr.replace(/^[^A-Za-z]|[^A-Za-z0-9]/g, function(m){ return '_0x' + m.charCodeAt(0).toString(16) + '_'; });
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
var getAttr;
|
|
396
|
+
|
|
397
|
+
// Good browsers
|
|
398
|
+
if (!getAttributeDodgy) {
|
|
399
|
+
getAttr = function(attr){ return 'var '+varForAttr(attr)+' = el.getAttribute("'+attr+'");' ; };
|
|
400
|
+
}
|
|
401
|
+
// IE 6, 7
|
|
402
|
+
else {
|
|
403
|
+
// On IE 6 + 7, getAttribute still has to be called with DOM property mirror name, not attribute name. Map attributes to those names
|
|
404
|
+
var getAttrIEMap = { 'class': 'className', 'for': 'htmlFor' };
|
|
405
|
+
|
|
406
|
+
getAttr = function(attr) {
|
|
407
|
+
var ieattr = getAttrIEMap[attr] || attr;
|
|
408
|
+
return 'var '+varForAttr(attr)+' = el.getAttribute("'+ieattr+'",2) || (el.getAttributeNode("'+attr+'")||{}).nodeValue;';
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**** ATTRIBUTE COMPARITORS ****/
|
|
413
|
+
|
|
414
|
+
var attrchecks = {
|
|
415
|
+
'-': '!K',
|
|
416
|
+
'=': 'K != "V"',
|
|
417
|
+
'!=': 'K == "V"',
|
|
418
|
+
'~=': '_WS_K.indexOf(" V ") == -1',
|
|
419
|
+
'^=': '!K || K.indexOf("V") != 0',
|
|
420
|
+
'*=': '!K || K.indexOf("V") == -1',
|
|
421
|
+
'$=': '!K || K.substr(K.length-"V".length) != "V"'
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**** STATE TRACKER ****/
|
|
425
|
+
|
|
426
|
+
var State = $.selector.State = Base.extend({
|
|
427
|
+
init: function(){
|
|
428
|
+
this.reset();
|
|
429
|
+
},
|
|
430
|
+
reset: function() {
|
|
431
|
+
this.attrs = {}; this.wsattrs = {};
|
|
432
|
+
},
|
|
433
|
+
|
|
434
|
+
prev: function(){
|
|
435
|
+
this.reset();
|
|
436
|
+
if (hasElementTraversal) return 'el = el.previousElementSibling';
|
|
437
|
+
return 'while((el = el.previousSibling) && el.nodeType != 1) {}';
|
|
438
|
+
},
|
|
439
|
+
next: function() {
|
|
440
|
+
this.reset();
|
|
441
|
+
if (hasElementTraversal) return 'el = el.nextElementSibling';
|
|
442
|
+
return 'while((el = el.nextSibling) && el.nodeType != 1) {}';
|
|
443
|
+
},
|
|
444
|
+
prevLoop: function(body){
|
|
445
|
+
this.reset();
|
|
446
|
+
if (hasElementTraversal) return join([ 'while(el = el.previousElementSibling){', body]);
|
|
447
|
+
return join([
|
|
448
|
+
'while(el = el.previousSibling){',
|
|
449
|
+
'if (el.nodeType != 1) continue;',
|
|
450
|
+
body
|
|
451
|
+
]);
|
|
452
|
+
},
|
|
453
|
+
parent: function() {
|
|
454
|
+
this.reset();
|
|
455
|
+
return 'el = el.parentNode;';
|
|
456
|
+
},
|
|
457
|
+
parentLoop: function(body) {
|
|
458
|
+
this.reset();
|
|
459
|
+
return join([
|
|
460
|
+
'while((el = el.parentNode) && el.nodeType == 1){',
|
|
461
|
+
body,
|
|
462
|
+
'}'
|
|
463
|
+
]);
|
|
464
|
+
},
|
|
465
|
+
|
|
466
|
+
uses_attr: function(attr) {
|
|
467
|
+
if (this.attrs[attr]) return;
|
|
468
|
+
this.attrs[attr] = true;
|
|
469
|
+
return getAttr(attr);
|
|
470
|
+
},
|
|
471
|
+
uses_wsattr: function(attr) {
|
|
472
|
+
if (this.wsattrs[attr]) return;
|
|
473
|
+
this.wsattrs[attr] = true;
|
|
474
|
+
return join([this.uses_attr(attr), 'var _WS_'+varForAttr(attr)+' = " "+'+varForAttr(attr)+'+" ";']);
|
|
475
|
+
},
|
|
476
|
+
|
|
477
|
+
save: function(lbl) {
|
|
478
|
+
return 'var el'+lbl+' = el;';
|
|
479
|
+
},
|
|
480
|
+
restore: function(lbl) {
|
|
481
|
+
this.reset();
|
|
482
|
+
return 'el = el'+lbl+';';
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
/**** PSEUDO-CLASS DETAILS ****/
|
|
487
|
+
|
|
488
|
+
var pseudoclschecks = {
|
|
489
|
+
'first-child': join([
|
|
490
|
+
'var cel = el;',
|
|
491
|
+
'while(cel = cel.previousSibling){ if (cel.nodeType === 1) BAD; }'
|
|
492
|
+
]),
|
|
493
|
+
'last-child': join([
|
|
494
|
+
'var cel = el;',
|
|
495
|
+
'while(cel = cel.nextSibling){ if (cel.nodeType === 1) BAD; }'
|
|
496
|
+
]),
|
|
497
|
+
'nth-child': function(a,b) {
|
|
498
|
+
var get_i = join([
|
|
499
|
+
'var i = 1, cel = el;',
|
|
500
|
+
'while(cel = cel.previousSibling){',
|
|
501
|
+
'if (cel.nodeType === 1) i++;',
|
|
502
|
+
'}'
|
|
503
|
+
]);
|
|
504
|
+
|
|
505
|
+
if (a == 0) return join([
|
|
506
|
+
get_i,
|
|
507
|
+
'if (i- '+b+' != 0) BAD;'
|
|
508
|
+
]);
|
|
509
|
+
else if (b == 0 && a >= 0) return join([
|
|
510
|
+
get_i,
|
|
511
|
+
'if (i%'+a+' != 0 || i/'+a+' < 0) BAD;'
|
|
512
|
+
]);
|
|
513
|
+
else if (b == 0 && a < 0) return join([
|
|
514
|
+
'BAD;'
|
|
515
|
+
]);
|
|
516
|
+
else return join([
|
|
517
|
+
get_i,
|
|
518
|
+
'if ((i- '+b+')%'+a+' != 0 || (i- '+b+')/'+a+' < 0) BAD;'
|
|
519
|
+
]);
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
// Needs to refence contents of object, so must be injected after definition
|
|
524
|
+
pseudoclschecks['only-child'] = join([
|
|
525
|
+
pseudoclschecks['first-child'],
|
|
526
|
+
pseudoclschecks['last-child']
|
|
527
|
+
]);
|
|
528
|
+
|
|
529
|
+
/**** SimpleSelector ****/
|
|
530
|
+
|
|
531
|
+
$.selector.SimpleSelector.addMethod('compile', function(el) {
|
|
532
|
+
var js = [];
|
|
533
|
+
|
|
534
|
+
/* Check against element name */
|
|
535
|
+
if (this.tag && this.tag != '*') {
|
|
536
|
+
js[js.length] = 'if (el.tagName != "'+this.tag.toUpperCase()+'") BAD;';
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/* Check against ID */
|
|
540
|
+
if (this.id) {
|
|
541
|
+
js[js.length] = el.uses_attr('id');
|
|
542
|
+
js[js.length] = 'if (_id !== "'+this.id+'") BAD;';
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/* Build className checking variable */
|
|
546
|
+
if (this.classes.length) {
|
|
547
|
+
js[js.length] = el.uses_wsattr('class');
|
|
548
|
+
|
|
549
|
+
/* Check against class names */
|
|
550
|
+
$.each(this.classes, function(i, cls){
|
|
551
|
+
js[js.length] = 'if (_WS__class.indexOf(" '+cls+' ") == -1) BAD;';
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/* Check against attributes */
|
|
556
|
+
$.each(this.attrs, function(i, attr){
|
|
557
|
+
js[js.length] = (attr[1] == '~=') ? el.uses_wsattr(attr[0]) : el.uses_attr(attr[0]);
|
|
558
|
+
var check = attrchecks[ attr[1] || '-' ];
|
|
559
|
+
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] );
|
|
560
|
+
js[js.length] = 'if ('+check+') BAD;';
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
/* Check against nots */
|
|
564
|
+
$.each(this.nots, function(i, not){
|
|
565
|
+
var lbl = ++lbl_id;
|
|
566
|
+
var func = join([
|
|
567
|
+
'l'+lbl+':{',
|
|
568
|
+
not.compile(el).replace(BAD, 'break l'+lbl).replace(GOOD, 'BAD'),
|
|
569
|
+
'}'
|
|
570
|
+
]);
|
|
571
|
+
|
|
572
|
+
if (!(not instanceof $.selector.SimpleSelector)) func = join([
|
|
573
|
+
el.save(lbl),
|
|
574
|
+
func,
|
|
575
|
+
el.restore(lbl)
|
|
576
|
+
]);
|
|
577
|
+
|
|
578
|
+
js[js.length] = func;
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
/* Check against pseudo-classes */
|
|
582
|
+
$.each(this.pseudo_classes, function(i, pscls){
|
|
583
|
+
var check = pseudoclschecks[pscls[0]];
|
|
584
|
+
if (check) {
|
|
585
|
+
js[js.length] = ( typeof check == 'function' ? check.apply(this, pscls[1]) : check );
|
|
586
|
+
}
|
|
587
|
+
else if (check = $.find.selectors.filters[pscls[0]]) {
|
|
588
|
+
if (funcToString) {
|
|
589
|
+
js[js.length] = funcToString(check).replace(/elem/g,'el').replace(/return([^;]+);/,'if (!($1)) BAD;');
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
js[js.length] = 'if (!$.find.selectors.filters.'+pscls[0]+'(el)) BAD;';
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
js[js.length] = 'GOOD';
|
|
598
|
+
|
|
599
|
+
/* Pass */
|
|
600
|
+
return join(js);
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
var lbl_id = 0;
|
|
604
|
+
/** Turns an compiled fragment into the first part of a combination */
|
|
605
|
+
function as_subexpr(f) {
|
|
606
|
+
if (f.complex)
|
|
607
|
+
return join([
|
|
608
|
+
'l'+(++lbl_id)+':{',
|
|
609
|
+
f.replace(GOOD, 'break l'+lbl_id),
|
|
610
|
+
'}'
|
|
611
|
+
]);
|
|
612
|
+
else
|
|
613
|
+
return f.replace(GOOD, '');
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
var combines = {
|
|
617
|
+
' ': function(el, f1, f2) {
|
|
618
|
+
return join_complex([
|
|
619
|
+
f2,
|
|
620
|
+
'while(true){',
|
|
621
|
+
el.parent(),
|
|
622
|
+
'if (!el || el.nodeType !== 1) BAD;',
|
|
623
|
+
f1.compile(el).replace(BAD, 'continue'),
|
|
624
|
+
'}'
|
|
625
|
+
]);
|
|
626
|
+
},
|
|
627
|
+
|
|
628
|
+
'>': function(el, f1, f2) {
|
|
629
|
+
return join([
|
|
630
|
+
f2,
|
|
631
|
+
el.parent(),
|
|
632
|
+
'if (!el || el.nodeType !== 1) BAD;',
|
|
633
|
+
f1.compile(el)
|
|
634
|
+
]);
|
|
635
|
+
},
|
|
636
|
+
|
|
637
|
+
'~': function(el, f1, f2) {
|
|
638
|
+
return join_complex([
|
|
639
|
+
f2,
|
|
640
|
+
el.prevLoop(),
|
|
641
|
+
f1.compile(el).replace(BAD, 'continue'),
|
|
642
|
+
'}',
|
|
643
|
+
'BAD;'
|
|
644
|
+
]);
|
|
645
|
+
},
|
|
646
|
+
|
|
647
|
+
'+': function(el, f1, f2) {
|
|
648
|
+
return join([
|
|
649
|
+
f2,
|
|
650
|
+
el.prev(),
|
|
651
|
+
'if (!el) BAD;',
|
|
652
|
+
f1.compile(el)
|
|
653
|
+
]);
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
$.selector.Selector.addMethod('compile', function(el) {
|
|
658
|
+
var l = this.parts.length;
|
|
659
|
+
|
|
660
|
+
var expr = this.parts[--l].compile(el);
|
|
661
|
+
while (l) {
|
|
662
|
+
var combinator = this.parts[--l];
|
|
663
|
+
expr = combines[combinator](el, this.parts[--l], as_subexpr(expr));
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return expr;
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
$.selector.SelectorsGroup.addMethod('compile', function(el) {
|
|
670
|
+
var expr = [], lbl = ++lbl_id;
|
|
671
|
+
|
|
672
|
+
for (var i=0; i < this.parts.length; i++) {
|
|
673
|
+
expr[expr.length] = join([
|
|
674
|
+
i == 0 ? el.save(lbl) : el.restore(lbl),
|
|
675
|
+
'l'+lbl+'_'+i+':{',
|
|
676
|
+
this.parts[i].compile(el).replace(BAD, 'break l'+lbl+'_'+i),
|
|
677
|
+
'}'
|
|
678
|
+
]);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
expr[expr.length] = 'BAD;';
|
|
682
|
+
return join(expr);
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
$.selector.SelectorBase.addMethod('matches', function(el){
|
|
686
|
+
this.matches = new Function('el', join([
|
|
687
|
+
'if (!el) return false;',
|
|
688
|
+
this.compile(new State()).replace(BAD, 'return false').replace(GOOD, 'return true')
|
|
689
|
+
]));
|
|
690
|
+
return this.matches(el);
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
})(jQuery);
|
|
694
|
+
|
|
695
|
+
;
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
/* src/jquery.focusinout.js */
|
|
699
|
+
|
|
700
|
+
(function($){
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Add focusin and focusout support to bind and live for browers other than IE. Designed to be usable in a delegated fashion (like $.live)
|
|
704
|
+
* Copyright (c) 2007 Jörn Zaefferer
|
|
705
|
+
*/
|
|
706
|
+
$.support.focusInOut = !!($.browser.msie);
|
|
707
|
+
if (!$.support.focusInOut) {
|
|
708
|
+
// Emulate focusin and focusout by binding focus and blur in capturing mode
|
|
709
|
+
$.each({focus: 'focusin', blur: 'focusout'}, function(original, fix){
|
|
710
|
+
$.event.special[fix] = {
|
|
711
|
+
setup: function(){
|
|
712
|
+
if (!this.addEventListener) return false;
|
|
713
|
+
this.addEventListener(original, $.event.special[fix].handler, true);
|
|
714
|
+
},
|
|
715
|
+
teardown: function(){
|
|
716
|
+
if (!this.removeEventListener) return false;
|
|
717
|
+
this.removeEventListener(original, $.event.special[fix].handler, true);
|
|
718
|
+
},
|
|
719
|
+
handler: function(e){
|
|
720
|
+
arguments[0] = $.event.fix(e);
|
|
721
|
+
arguments[0].type = fix;
|
|
722
|
+
return $.event.handle.apply(this, arguments);
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
(function(){
|
|
729
|
+
//IE has some trouble with focusout with select and keyboard navigation
|
|
730
|
+
var activeFocus = null;
|
|
731
|
+
|
|
732
|
+
$(document)
|
|
733
|
+
.bind('focusin', function(e){
|
|
734
|
+
var target = e.realTarget || e.target;
|
|
735
|
+
if (activeFocus && activeFocus !== target) {
|
|
736
|
+
e.type = 'focusout';
|
|
737
|
+
$(activeFocus).trigger(e);
|
|
738
|
+
e.type = 'focusin';
|
|
739
|
+
e.target = target;
|
|
740
|
+
}
|
|
741
|
+
activeFocus = target;
|
|
742
|
+
})
|
|
743
|
+
.bind('focusout', function(e){
|
|
744
|
+
activeFocus = null;
|
|
745
|
+
});
|
|
746
|
+
})();
|
|
747
|
+
|
|
748
|
+
})(jQuery);;
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
/* src/jquery.entwine.js */
|
|
752
|
+
|
|
753
|
+
try {
|
|
754
|
+
console.log;
|
|
755
|
+
}
|
|
756
|
+
catch (e) {
|
|
757
|
+
window.console = undefined;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
(function($) {
|
|
761
|
+
|
|
762
|
+
var namespaces = {};
|
|
763
|
+
|
|
764
|
+
$.entwine = function() {
|
|
765
|
+
$.fn.entwine.apply(null, arguments);
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* A couple of utility functions for accessing the store outside of this closure, and for making things
|
|
770
|
+
* operate in a little more easy-to-test manner
|
|
771
|
+
*/
|
|
772
|
+
$.extend($.entwine, {
|
|
773
|
+
/**
|
|
774
|
+
* Get all the namespaces. Useful for introspection? Internal interface of Namespace not guaranteed consistant
|
|
775
|
+
*/
|
|
776
|
+
namespaces: namespaces,
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Remove all entwine rules
|
|
780
|
+
*/
|
|
781
|
+
clear_all_rules: function() {
|
|
782
|
+
// Remove proxy functions
|
|
783
|
+
for (var k in $.fn) { if ($.fn[k].isentwinemethod) delete $.fn[k]; }
|
|
784
|
+
// Remove bound events - TODO: Make this pluggable, so this code can be moved to jquery.entwine.events.js
|
|
785
|
+
$(document).unbind('.entwine');
|
|
786
|
+
// Remove namespaces, and start over again
|
|
787
|
+
namespaces = $.entwine.namespaces = {};
|
|
788
|
+
},
|
|
789
|
+
|
|
790
|
+
WARN_LEVEL_NONE: 0,
|
|
791
|
+
WARN_LEVEL_IMPORTANT: 1,
|
|
792
|
+
WARN_LEVEL_BESTPRACTISE: 2,
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* Warning level. Set to a higher level to get warnings dumped to console.
|
|
796
|
+
*/
|
|
797
|
+
warningLevel: 0,
|
|
798
|
+
|
|
799
|
+
/** Utility to optionally display warning messages depending on level */
|
|
800
|
+
warn: function(message, level) {
|
|
801
|
+
if (level <= $.entwine.warningLevel && console && console.warn) {
|
|
802
|
+
console.warn(message);
|
|
803
|
+
if (console.trace) console.trace();
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
|
|
807
|
+
warn_exception: function(where, /* optional: */ on, e) {
|
|
808
|
+
if ($.entwine.WARN_LEVEL_IMPORTANT <= $.entwine.warningLevel && console && console.warn) {
|
|
809
|
+
if (arguments.length == 2) { e = on; on = null; }
|
|
810
|
+
|
|
811
|
+
if (on) console.warn('Uncaught exception',e,'in',where,'on',on);
|
|
812
|
+
else console.warn('Uncaught exception',e,'in',where);
|
|
813
|
+
|
|
814
|
+
if (e.stack) console.warn("Stack Trace:\n" + e.stack);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
/** Stores a count of definitions, so that we can sort identical selectors by definition order */
|
|
821
|
+
var rulecount = 0;
|
|
822
|
+
|
|
823
|
+
var Rule = Base.extend({
|
|
824
|
+
init: function(selector, name) {
|
|
825
|
+
this.selector = selector;
|
|
826
|
+
this.specifity = selector.specifity();
|
|
827
|
+
this.important = 0;
|
|
828
|
+
this.name = name;
|
|
829
|
+
this.rulecount = rulecount++;
|
|
830
|
+
}
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
Rule.compare = function(a, b) {
|
|
834
|
+
var as = a.specifity, bs = b.specifity;
|
|
835
|
+
|
|
836
|
+
return (a.important - b.important) ||
|
|
837
|
+
(as[0] - bs[0]) ||
|
|
838
|
+
(as[1] - bs[1]) ||
|
|
839
|
+
(as[2] - bs[2]) ||
|
|
840
|
+
(a.rulecount - b.rulecount) ;
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
$.entwine.RuleList = function() {
|
|
844
|
+
var list = [];
|
|
845
|
+
|
|
846
|
+
list.addRule = function(selector, name){
|
|
847
|
+
var rule = Rule(selector, name);
|
|
848
|
+
|
|
849
|
+
list[list.length] = rule;
|
|
850
|
+
list.sort(Rule.compare);
|
|
851
|
+
|
|
852
|
+
return rule;
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
return list;
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
var handlers = [];
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* A Namespace holds all the information needed for adding entwine methods to a namespace (including the _null_ namespace)
|
|
862
|
+
*/
|
|
863
|
+
$.entwine.Namespace = Base.extend({
|
|
864
|
+
init: function(name){
|
|
865
|
+
if (name && !name.match(/^[A-Za-z0-9.]+$/)) $.entwine.warn('Entwine namespace '+name+' is not formatted as period seperated identifiers', $.entwine.WARN_LEVEL_BESTPRACTISE);
|
|
866
|
+
name = name || '__base';
|
|
867
|
+
|
|
868
|
+
this.name = name;
|
|
869
|
+
this.store = {};
|
|
870
|
+
|
|
871
|
+
namespaces[name] = this;
|
|
872
|
+
|
|
873
|
+
if (name == "__base") {
|
|
874
|
+
this.injectee = $.fn;
|
|
875
|
+
this.$ = $;
|
|
876
|
+
}
|
|
877
|
+
else {
|
|
878
|
+
// We're in a namespace, so we build a Class that subclasses the jQuery Object Class to inject namespace functions into
|
|
879
|
+
|
|
880
|
+
// jQuery 1.5 already provides a nice way to subclass, so use it
|
|
881
|
+
if ($.sub) {
|
|
882
|
+
this.$ = $.sub();
|
|
883
|
+
this.injectee = this.$.prototype;
|
|
884
|
+
}
|
|
885
|
+
// For jQuery < 1.5 we have to do it ourselves
|
|
886
|
+
else {
|
|
887
|
+
var subfn = function(){};
|
|
888
|
+
this.injectee = subfn.prototype = new $;
|
|
889
|
+
|
|
890
|
+
// And then we provide an overriding $ that returns objects of our new Class, and an overriding pushStack to catch further selection building
|
|
891
|
+
var bound$ = this.$ = function(a) {
|
|
892
|
+
// Try the simple way first
|
|
893
|
+
var jq = $.fn.init.apply(new subfn(), arguments);
|
|
894
|
+
if (jq instanceof subfn) return jq;
|
|
895
|
+
|
|
896
|
+
// That didn't return a bound object, so now we need to copy it
|
|
897
|
+
var rv = new subfn();
|
|
898
|
+
rv.selector = jq.selector; rv.context = jq.context; var i = rv.length = jq.length;
|
|
899
|
+
while (i--) rv[i] = jq[i];
|
|
900
|
+
return rv;
|
|
901
|
+
};
|
|
902
|
+
|
|
903
|
+
this.injectee.pushStack = function(elems, name, selector){
|
|
904
|
+
var ret = bound$(elems);
|
|
905
|
+
|
|
906
|
+
// Add the old object onto the stack (as a reference)
|
|
907
|
+
ret.prevObject = this;
|
|
908
|
+
ret.context = this.context;
|
|
909
|
+
|
|
910
|
+
if ( name === "find" ) ret.selector = this.selector + (this.selector ? " " : "") + selector;
|
|
911
|
+
else if ( name ) ret.selector = this.selector + "." + name + "(" + selector + ")";
|
|
912
|
+
|
|
913
|
+
// Return the newly-formed element set
|
|
914
|
+
return ret;
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
// Copy static functions through from $ to this.$ so e.g. $.ajax still works
|
|
918
|
+
// @bug, @cantfix: Any class functions added to $ after this call won't get mirrored through
|
|
919
|
+
$.extend(this.$, $);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
// We override entwine to inject the name of this namespace when defining blocks inside this namespace
|
|
923
|
+
var entwine_wrapper = this.injectee.entwine = function(spacename) {
|
|
924
|
+
var args = arguments;
|
|
925
|
+
|
|
926
|
+
if (!spacename || typeof spacename != 'string') { args = $.makeArray(args); args.unshift(name); }
|
|
927
|
+
else if (spacename.charAt(0) != '.') args[0] = name+'.'+spacename;
|
|
928
|
+
|
|
929
|
+
return $.fn.entwine.apply(this, args);
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
this.$.entwine = function() {
|
|
933
|
+
entwine_wrapper.apply(null, arguments);
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
for (var i = 0; i < handlers.length; i++) {
|
|
937
|
+
var handler = handlers[i], builder;
|
|
938
|
+
|
|
939
|
+
// Inject jQuery object method overrides
|
|
940
|
+
if (builder = handler.namespaceMethodOverrides) {
|
|
941
|
+
var overrides = builder(this);
|
|
942
|
+
for (var k in overrides) this.injectee[k] = overrides[k];
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Inject $.entwine function overrides
|
|
946
|
+
if (builder = handler.namespaceStaticOverrides) {
|
|
947
|
+
var overrides = builder(this);
|
|
948
|
+
for (var k in overrides) this.$.entwine[k] = overrides[k];
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Returns a function that does selector matching against the function list for a function name
|
|
956
|
+
* Used by proxy for all calls, and by ctorProxy to handle _super calls
|
|
957
|
+
* @param {String} name - name of the function as passed in the construction object
|
|
958
|
+
* @param {String} funcprop - the property on the Rule object that gives the actual function to call
|
|
959
|
+
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
|
|
960
|
+
*/
|
|
961
|
+
one: function(name, funcprop, basefunc) {
|
|
962
|
+
var namespace = this;
|
|
963
|
+
var funcs = this.store[name];
|
|
964
|
+
|
|
965
|
+
var one = function(el, args, i){
|
|
966
|
+
if (i === undefined) i = funcs.length;
|
|
967
|
+
while (i--) {
|
|
968
|
+
if (funcs[i].selector.matches(el)) {
|
|
969
|
+
var ret, tmp_i = el.i, tmp_f = el.f;
|
|
970
|
+
el.i = i; el.f = one;
|
|
971
|
+
try { ret = funcs[i][funcprop].apply(namespace.$(el), args); }
|
|
972
|
+
finally { el.i = tmp_i; el.f = tmp_f; }
|
|
973
|
+
return ret;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
// If we didn't find a entwine-defined function, but there is a non-entwine function to use as a base, try that
|
|
977
|
+
if (basefunc) return basefunc.apply(namespace.$(el), args);
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
return one;
|
|
981
|
+
},
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* A proxy is a function attached to a callable object (either the base jQuery.fn or a subspace object) which handles
|
|
985
|
+
* finding and calling the correct function for each member of the current jQuery context
|
|
986
|
+
* @param {String} name - name of the function as passed in the construction object
|
|
987
|
+
* @param {function} basefunc - the non-entwine function to use as the catch-all function at the bottom of the stack
|
|
988
|
+
*/
|
|
989
|
+
build_proxy: function(name, basefunc) {
|
|
990
|
+
var one = this.one(name, 'func', basefunc);
|
|
991
|
+
|
|
992
|
+
var prxy = function() {
|
|
993
|
+
var rv, ctx = $(this);
|
|
994
|
+
|
|
995
|
+
var i = ctx.length;
|
|
996
|
+
while (i--) rv = one(ctx[i], arguments);
|
|
997
|
+
return rv;
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
return prxy;
|
|
1001
|
+
},
|
|
1002
|
+
|
|
1003
|
+
bind_proxy: function(selector, name, func) {
|
|
1004
|
+
var rulelist = this.store[name] || (this.store[name] = $.entwine.RuleList());
|
|
1005
|
+
|
|
1006
|
+
var rule = rulelist.addRule(selector, name); rule.func = func;
|
|
1007
|
+
|
|
1008
|
+
if (!this.injectee.hasOwnProperty(name) || !this.injectee[name].isentwinemethod) {
|
|
1009
|
+
this.injectee[name] = this.build_proxy(name, this.injectee.hasOwnProperty(name) ? this.injectee[name] : null);
|
|
1010
|
+
this.injectee[name].isentwinemethod = true;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
if (!this.injectee[name].isentwinemethod) {
|
|
1014
|
+
$.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);
|
|
1015
|
+
}
|
|
1016
|
+
},
|
|
1017
|
+
|
|
1018
|
+
add: function(selector, data) {
|
|
1019
|
+
// For every item in the hash, try ever method handler, until one returns true
|
|
1020
|
+
for (var k in data) {
|
|
1021
|
+
var v = data[k];
|
|
1022
|
+
|
|
1023
|
+
for (var i = 0; i < handlers.length; i++) {
|
|
1024
|
+
if (handlers[i].bind && handlers[i].bind.call(this, selector, k, v)) break;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
},
|
|
1028
|
+
|
|
1029
|
+
has: function(ctx, name) {
|
|
1030
|
+
var rulelist = this.store[name];
|
|
1031
|
+
if (!rulelist) return false;
|
|
1032
|
+
|
|
1033
|
+
/* We go forward this time, since low specifity is likely to knock out a bunch of elements quickly */
|
|
1034
|
+
for (var i = 0 ; i < rulelist.length; i++) {
|
|
1035
|
+
ctx = ctx.not(rulelist[i].selector);
|
|
1036
|
+
if (!ctx.length) return true;
|
|
1037
|
+
}
|
|
1038
|
+
return false;
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* 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.
|
|
1044
|
+
* The default handlers provided (and included by default) are event, ctor and properties
|
|
1045
|
+
*/
|
|
1046
|
+
$.entwine.Namespace.addHandler = function(handler) {
|
|
1047
|
+
for (var i = 0; i < handlers.length && handlers[i].order < handler.order; i++) { /* Pass */ }
|
|
1048
|
+
handlers.splice(i, 0, handler);
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
$.entwine.Namespace.addHandler({
|
|
1052
|
+
order: 50,
|
|
1053
|
+
|
|
1054
|
+
bind: function(selector, k, v){
|
|
1055
|
+
if ($.isFunction(v)) {
|
|
1056
|
+
this.bind_proxy(selector, k, v);
|
|
1057
|
+
return true;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
$.extend($.fn, {
|
|
1063
|
+
/**
|
|
1064
|
+
* Main entwine function. Used for new definitions, calling into a namespace (or forcing the base namespace) and entering a using block
|
|
1065
|
+
*
|
|
1066
|
+
*/
|
|
1067
|
+
entwine: function(spacename) {
|
|
1068
|
+
var i = 0;
|
|
1069
|
+
/* 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
|
|
1070
|
+
which have non-standard selectors like .parents(.foo).slice(0,1) */
|
|
1071
|
+
var selector = null;
|
|
1072
|
+
|
|
1073
|
+
/* By default we operator on the base namespace */
|
|
1074
|
+
var namespace = namespaces.__base || $.entwine.Namespace();
|
|
1075
|
+
|
|
1076
|
+
/* If the first argument is a string, then it's the name of a namespace. Look it up */
|
|
1077
|
+
if (typeof spacename == 'string') {
|
|
1078
|
+
if (spacename.charAt('0') == '.') spacename = spacename.substr(1);
|
|
1079
|
+
if (spacename) namespace = namespaces[spacename] || $.entwine.Namespace(spacename);
|
|
1080
|
+
i=1;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/* All remaining arguments should either be using blocks or definition hashs */
|
|
1084
|
+
while (i < arguments.length) {
|
|
1085
|
+
var res = arguments[i++];
|
|
1086
|
+
|
|
1087
|
+
// If it's a function, call it - either it's a using block or it's a namespaced entwine definition
|
|
1088
|
+
if ($.isFunction(res)) {
|
|
1089
|
+
if (res.length != 1) $.entwine.warn('Function block inside entwine definition does not take $ argument properly', $.entwine.WARN_LEVEL_IMPORTANT);
|
|
1090
|
+
res = res.call(namespace.$(this), namespace.$);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// If we have a entwine definition hash, inject it into namespace
|
|
1094
|
+
if (res) {
|
|
1095
|
+
if (selector === null) selector = this.selector ? $.selector(this.selector) : false;
|
|
1096
|
+
|
|
1097
|
+
if (selector) namespace.add(selector, res);
|
|
1098
|
+
else $.entwine.warn('Entwine block given to entwine call without selector. Make sure you call $(selector).entwine when defining blocks', $.entwine.WARN_LEVEL_IMPORTANT);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
/* Finally, return the jQuery object 'this' refers to, wrapped in the new namespace */
|
|
1103
|
+
return namespace.$(this);
|
|
1104
|
+
},
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
* Calls the next most specific version of the current entwine method
|
|
1108
|
+
*/
|
|
1109
|
+
_super: function(){
|
|
1110
|
+
var rv, i = this.length;
|
|
1111
|
+
while (i--) {
|
|
1112
|
+
var el = this[0];
|
|
1113
|
+
rv = el.f(el, arguments, el.i);
|
|
1114
|
+
}
|
|
1115
|
+
return rv;
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
})(jQuery);
|
|
1120
|
+
;
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
/* src/jquery.entwine.dommaybechanged.js */
|
|
1124
|
+
|
|
1125
|
+
(function($){
|
|
1126
|
+
|
|
1127
|
+
/** What to call to run a function 'soon'. Normally setTimeout, but for syncronous mode we override so soon === now */
|
|
1128
|
+
var runSoon = window.setTimeout;
|
|
1129
|
+
|
|
1130
|
+
/** The timer handle for the asyncronous matching call */
|
|
1131
|
+
var check_id = null;
|
|
1132
|
+
|
|
1133
|
+
/** Fire the change event. Only fires on the document node, so bind to that */
|
|
1134
|
+
var triggerEvent = function() {
|
|
1135
|
+
$(document).triggerHandler('DOMMaybeChanged');
|
|
1136
|
+
check_id = null;
|
|
1137
|
+
};
|
|
1138
|
+
|
|
1139
|
+
$.extend($.entwine, {
|
|
1140
|
+
/**
|
|
1141
|
+
* Make onmatch and onunmatch work in synchronous mode - that is, new elements will be detected immediately after
|
|
1142
|
+
* the DOM manipulation that made them match. This is only really useful for during testing, since it's pretty slow
|
|
1143
|
+
* (otherwise we'd make it the default).
|
|
1144
|
+
*/
|
|
1145
|
+
synchronous_mode: function() {
|
|
1146
|
+
if (check_id) clearTimeout(check_id); check_id = null;
|
|
1147
|
+
runSoon = function(func, delay){ func.call(this); return null; };
|
|
1148
|
+
},
|
|
1149
|
+
|
|
1150
|
+
/**
|
|
1151
|
+
* Trigger onmatch and onunmatch now - usefull for after DOM manipulation by methods other than through jQuery.
|
|
1152
|
+
* Called automatically on document.ready
|
|
1153
|
+
*/
|
|
1154
|
+
triggerMatching: function() {
|
|
1155
|
+
matching();
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
function registerMutateFunction() {
|
|
1160
|
+
$.each(arguments, function(i,func){
|
|
1161
|
+
var old = $.fn[func];
|
|
1162
|
+
$.fn[func] = function() {
|
|
1163
|
+
var rv = old.apply(this, arguments);
|
|
1164
|
+
if (!check_id) check_id = runSoon(triggerEvent, 100);
|
|
1165
|
+
return rv;
|
|
1166
|
+
};
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
function registerSetterGetterFunction() {
|
|
1171
|
+
$.each(arguments, function(i,func){
|
|
1172
|
+
var old = $.fn[func];
|
|
1173
|
+
$.fn[func] = function(a, b) {
|
|
1174
|
+
var rv = old.apply(this, arguments);
|
|
1175
|
+
if (!check_id && (b !== undefined || typeof a != 'string')) check_id = runSoon(triggerEvent, 100);
|
|
1176
|
+
return rv;
|
|
1177
|
+
};
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// Register core DOM manipulation methods
|
|
1182
|
+
registerMutateFunction('append', 'prepend', 'after', 'before', 'wrap', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove');
|
|
1183
|
+
registerSetterGetterFunction('attr');
|
|
1184
|
+
|
|
1185
|
+
// And on DOM ready, trigger matching once
|
|
1186
|
+
$(function(){ triggerEvent(); });
|
|
1187
|
+
|
|
1188
|
+
})(jQuery);;
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
/* src/jquery.entwine.events.js */
|
|
1192
|
+
|
|
1193
|
+
(function($) {
|
|
1194
|
+
|
|
1195
|
+
/** Taken from jQuery 1.5.2 for backwards compatibility */
|
|
1196
|
+
if ($.support.changeBubbles == undefined) {
|
|
1197
|
+
$.support.changeBubbles = true;
|
|
1198
|
+
|
|
1199
|
+
var el = document.createElement("div");
|
|
1200
|
+
eventName = "onchange";
|
|
1201
|
+
|
|
1202
|
+
if (el.attachEvent) {
|
|
1203
|
+
var isSupported = (eventName in el);
|
|
1204
|
+
if (!isSupported) {
|
|
1205
|
+
el.setAttribute(eventName, "return;");
|
|
1206
|
+
isSupported = typeof el[eventName] === "function";
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
$.support.changeBubbles = isSupported;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/* Return true if node b is the same as, or is a descendant of, node a */
|
|
1214
|
+
if (document.compareDocumentPosition) {
|
|
1215
|
+
var is_or_contains = function(a, b) {
|
|
1216
|
+
return a && b && (a == b || !!(a.compareDocumentPosition(b) & 16));
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
var is_or_contains = function(a, b) {
|
|
1221
|
+
return a && b && (a == b || (a.contains ? a.contains(b) : true));
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
/* Add the methods to handle event binding to the Namespace class */
|
|
1226
|
+
$.entwine.Namespace.addMethods({
|
|
1227
|
+
build_event_proxy: function(name) {
|
|
1228
|
+
var one = this.one(name, 'func');
|
|
1229
|
+
|
|
1230
|
+
var prxy = function(e, data) {
|
|
1231
|
+
// For events that do not bubble we manually trigger delegation (see delegate_submit below)
|
|
1232
|
+
// If this event is a manual trigger, the event we actually want to bubble is attached as a property of the passed event
|
|
1233
|
+
e = e.delegatedEvent || e;
|
|
1234
|
+
|
|
1235
|
+
var el = e.target;
|
|
1236
|
+
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
|
1237
|
+
var ret = one(el, arguments);
|
|
1238
|
+
if (ret !== undefined) e.result = ret;
|
|
1239
|
+
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
|
1240
|
+
|
|
1241
|
+
el = el.parentNode;
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
|
|
1245
|
+
return prxy;
|
|
1246
|
+
},
|
|
1247
|
+
|
|
1248
|
+
build_mouseenterleave_proxy: function(name) {
|
|
1249
|
+
var one = this.one(name, 'func');
|
|
1250
|
+
|
|
1251
|
+
var prxy = function(e) {
|
|
1252
|
+
var el = e.target;
|
|
1253
|
+
var rel = e.relatedTarget;
|
|
1254
|
+
|
|
1255
|
+
while (el && el.nodeType == 1 && !e.isPropagationStopped()) {
|
|
1256
|
+
/* We know el contained target. If it also contains relatedTarget then we didn't mouseenter / leave. What's more, every ancestor will also
|
|
1257
|
+
contan el and rel, and so we can just stop bubbling */
|
|
1258
|
+
if (is_or_contains(el, rel)) break;
|
|
1259
|
+
|
|
1260
|
+
var ret = one(el, arguments);
|
|
1261
|
+
if (ret !== undefined) e.result = ret;
|
|
1262
|
+
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
|
1263
|
+
|
|
1264
|
+
el = el.parentNode;
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
|
|
1268
|
+
return prxy;
|
|
1269
|
+
},
|
|
1270
|
+
|
|
1271
|
+
build_change_proxy: function(name) {
|
|
1272
|
+
var one = this.one(name, 'func');
|
|
1273
|
+
|
|
1274
|
+
/*
|
|
1275
|
+
This change bubble emulation code is taken mostly from jQuery 1.6 - unfortunately we can't easily reuse any of
|
|
1276
|
+
it without duplication, so we'll have to re-migrate any bugfixes
|
|
1277
|
+
*/
|
|
1278
|
+
|
|
1279
|
+
// Get the value of an item. Isn't supposed to be interpretable, just stable for some value, and different
|
|
1280
|
+
// once the value changes
|
|
1281
|
+
var getVal = function( elem ) {
|
|
1282
|
+
var type = elem.type, val = elem.value;
|
|
1283
|
+
|
|
1284
|
+
if (type === "radio" || type === "checkbox") {
|
|
1285
|
+
val = elem.checked;
|
|
1286
|
+
}
|
|
1287
|
+
else if (type === "select-multiple") {
|
|
1288
|
+
val = "";
|
|
1289
|
+
if (elem.selectedIndex > -1) {
|
|
1290
|
+
val = jQuery.map(elem.options, function(elem){ return elem.selected; }).join("-");
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
else if (jQuery.nodeName(elem, "select")) {
|
|
1294
|
+
val = elem.selectedIndex;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
return val;
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
// Test if a node name is a form input
|
|
1301
|
+
var rformElems = /^(?:textarea|input|select)$/i;
|
|
1302
|
+
|
|
1303
|
+
// Check if this event is a change, and bubble the change event if it is
|
|
1304
|
+
var testChange = function(e) {
|
|
1305
|
+
var elem = e.target, data, val;
|
|
1306
|
+
|
|
1307
|
+
if (!rformElems.test(elem.nodeName) || elem.readOnly) return;
|
|
1308
|
+
|
|
1309
|
+
data = jQuery.data(elem, "_entwine_change_data");
|
|
1310
|
+
val = getVal(elem);
|
|
1311
|
+
|
|
1312
|
+
// the current data will be also retrieved by beforeactivate
|
|
1313
|
+
if (e.type !== "focusout" || elem.type !== "radio") {
|
|
1314
|
+
jQuery.data(elem, "_entwine_change_data", val);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
if (data === undefined || val === data) return;
|
|
1318
|
+
|
|
1319
|
+
if (data != null || val) {
|
|
1320
|
+
e.type = "change";
|
|
1321
|
+
|
|
1322
|
+
while (elem && elem.nodeType == 1 && !e.isPropagationStopped()) {
|
|
1323
|
+
var ret = one(elem, arguments);
|
|
1324
|
+
if (ret !== undefined) e.result = ret;
|
|
1325
|
+
if (ret === false) { e.preventDefault(); e.stopPropagation(); }
|
|
1326
|
+
|
|
1327
|
+
elem = elem.parentNode;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1332
|
+
// The actual proxy - responds to several events, some of which triger a change check, some
|
|
1333
|
+
// of which just store the value for future change checks
|
|
1334
|
+
var prxy = function(e) {
|
|
1335
|
+
var event = e.type, elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
|
|
1336
|
+
|
|
1337
|
+
switch (event) {
|
|
1338
|
+
case 'focusout':
|
|
1339
|
+
case 'beforedeactivate':
|
|
1340
|
+
testChange.apply(this, arguments);
|
|
1341
|
+
break;
|
|
1342
|
+
|
|
1343
|
+
case 'click':
|
|
1344
|
+
if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
|
|
1345
|
+
testChange.apply(this, arguments);
|
|
1346
|
+
}
|
|
1347
|
+
break;
|
|
1348
|
+
|
|
1349
|
+
// Change has to be called before submit
|
|
1350
|
+
// Keydown will be called before keypress, which is used in submit-event delegation
|
|
1351
|
+
case 'keydown':
|
|
1352
|
+
if (
|
|
1353
|
+
(e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
|
|
1354
|
+
(e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
|
|
1355
|
+
type === "select-multiple"
|
|
1356
|
+
) {
|
|
1357
|
+
testChange.apply(this, arguments);
|
|
1358
|
+
}
|
|
1359
|
+
break;
|
|
1360
|
+
|
|
1361
|
+
// Beforeactivate happens also before the previous element is blurred
|
|
1362
|
+
// with this event you can't trigger a change event, but you can store
|
|
1363
|
+
// information
|
|
1364
|
+
case 'focusin':
|
|
1365
|
+
case 'beforeactivate':
|
|
1366
|
+
jQuery.data( elem, "_entwine_change_data", getVal(elem) );
|
|
1367
|
+
break;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
return prxy;
|
|
1372
|
+
},
|
|
1373
|
+
|
|
1374
|
+
bind_event: function(selector, name, func, event) {
|
|
1375
|
+
var funcs = this.store[name] || (this.store[name] = $.entwine.RuleList()) ;
|
|
1376
|
+
var proxies = funcs.proxies || (funcs.proxies = {});
|
|
1377
|
+
|
|
1378
|
+
var rule = funcs.addRule(selector, name); rule.func = func;
|
|
1379
|
+
|
|
1380
|
+
if (!proxies[name]) {
|
|
1381
|
+
switch (name) {
|
|
1382
|
+
case 'onmouseenter':
|
|
1383
|
+
proxies[name] = this.build_mouseenterleave_proxy(name);
|
|
1384
|
+
event = 'mouseover';
|
|
1385
|
+
break;
|
|
1386
|
+
case 'onmouseleave':
|
|
1387
|
+
proxies[name] = this.build_mouseenterleave_proxy(name);
|
|
1388
|
+
event = 'mouseout';
|
|
1389
|
+
break;
|
|
1390
|
+
case 'onchange':
|
|
1391
|
+
if (!$.support.changeBubbles) {
|
|
1392
|
+
proxies[name] = this.build_change_proxy(name);
|
|
1393
|
+
event = 'click keydown focusin focusout beforeactivate beforedeactivate';
|
|
1394
|
+
}
|
|
1395
|
+
break;
|
|
1396
|
+
case 'onsubmit':
|
|
1397
|
+
event = 'delegatedSubmit';
|
|
1398
|
+
break;
|
|
1399
|
+
case 'onfocus':
|
|
1400
|
+
case 'onblur':
|
|
1401
|
+
$.entwine.warn('Event '+event+' not supported - using focusin / focusout instead', $.entwine.WARN_LEVEL_IMPORTANT);
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// If none of the special handlers created a proxy, use the generic proxy
|
|
1405
|
+
if (!proxies[name]) proxies[name] = this.build_event_proxy(name);
|
|
1406
|
+
|
|
1407
|
+
$(document).bind(event.replace(/(\s+|$)/g, '.entwine$1'), proxies[name]);
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
});
|
|
1411
|
+
|
|
1412
|
+
$.entwine.Namespace.addHandler({
|
|
1413
|
+
order: 40,
|
|
1414
|
+
|
|
1415
|
+
bind: function(selector, k, v){
|
|
1416
|
+
var match, event;
|
|
1417
|
+
if ($.isFunction(v) && (match = k.match(/^on(.*)/))) {
|
|
1418
|
+
event = match[1];
|
|
1419
|
+
this.bind_event(selector, k, v, event);
|
|
1420
|
+
return true;
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
// Find all forms and bind onsubmit to trigger on the document too.
|
|
1426
|
+
// This is the only event that can't be grabbed via delegation
|
|
1427
|
+
|
|
1428
|
+
var form_binding_cache = $([]); // A cache for already-handled form elements
|
|
1429
|
+
var delegate_submit = function(e, data){
|
|
1430
|
+
var delegationEvent = $.Event('delegatedSubmit'); delegationEvent.delegatedEvent = e;
|
|
1431
|
+
return $(document).trigger(delegationEvent, data);
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1434
|
+
$(document).bind('DOMMaybeChanged', function(){
|
|
1435
|
+
var forms = $('form');
|
|
1436
|
+
// Only bind to forms we haven't processed yet
|
|
1437
|
+
forms.not(form_binding_cache).bind('submit', delegate_submit);
|
|
1438
|
+
// Then remember the current set of forms
|
|
1439
|
+
form_binding_cache = forms;
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1442
|
+
})(jQuery);
|
|
1443
|
+
;
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
/* src/jquery.entwine.ctors.js */
|
|
1447
|
+
|
|
1448
|
+
(function($) {
|
|
1449
|
+
|
|
1450
|
+
/* Add the methods to handle constructor & destructor binding to the Namespace class */
|
|
1451
|
+
$.entwine.Namespace.addMethods({
|
|
1452
|
+
bind_condesc: function(selector, name, func) {
|
|
1453
|
+
var ctors = this.store.ctors || (this.store.ctors = $.entwine.RuleList()) ;
|
|
1454
|
+
|
|
1455
|
+
var rule;
|
|
1456
|
+
for (var i = 0 ; i < ctors.length; i++) {
|
|
1457
|
+
if (ctors[i].selector.selector == selector.selector) {
|
|
1458
|
+
rule = ctors[i]; break;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
if (!rule) {
|
|
1462
|
+
rule = ctors.addRule(selector, 'ctors');
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
rule[name] = func;
|
|
1466
|
+
|
|
1467
|
+
if (!ctors[name+'proxy']) {
|
|
1468
|
+
var one = this.one('ctors', name);
|
|
1469
|
+
var namespace = this;
|
|
1470
|
+
|
|
1471
|
+
var proxy = function(els, i, func) {
|
|
1472
|
+
var j = els.length;
|
|
1473
|
+
while (j--) {
|
|
1474
|
+
var el = els[j];
|
|
1475
|
+
|
|
1476
|
+
var tmp_i = el.i, tmp_f = el.f;
|
|
1477
|
+
el.i = i; el.f = one;
|
|
1478
|
+
|
|
1479
|
+
try { func.call(namespace.$(el)); }
|
|
1480
|
+
catch(e) { $.entwine.warn_exception(name, el, e); }
|
|
1481
|
+
finally { el.i = tmp_i; el.f = tmp_f; }
|
|
1482
|
+
}
|
|
1483
|
+
};
|
|
1484
|
+
|
|
1485
|
+
ctors[name+'proxy'] = proxy;
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
});
|
|
1489
|
+
|
|
1490
|
+
$.entwine.Namespace.addHandler({
|
|
1491
|
+
order: 30,
|
|
1492
|
+
|
|
1493
|
+
bind: function(selector, k, v) {
|
|
1494
|
+
if ($.isFunction(v) && (k == 'onmatch' || k == 'onunmatch')) {
|
|
1495
|
+
this.bind_condesc(selector, k, v);
|
|
1496
|
+
return true;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
/**
|
|
1502
|
+
* Finds all the elements that now match a different rule (or have been removed) and call onmatch on onunmatch as appropriate
|
|
1503
|
+
*
|
|
1504
|
+
* Because this has to scan the DOM, and is therefore fairly slow, this is normally triggered off a short timeout, so that
|
|
1505
|
+
* a series of DOM manipulations will only trigger this once.
|
|
1506
|
+
*
|
|
1507
|
+
* The downside of this is that things like:
|
|
1508
|
+
* $('#foo').addClass('tabs'); $('#foo').tabFunctionBar();
|
|
1509
|
+
* won't work.
|
|
1510
|
+
*/
|
|
1511
|
+
$(document).bind('DOMMaybeChanged', function(){
|
|
1512
|
+
// For every namespace
|
|
1513
|
+
for (var k in $.entwine.namespaces) {
|
|
1514
|
+
// That has constructors or destructors
|
|
1515
|
+
var ctors = $.entwine.namespaces[k].store.ctors;
|
|
1516
|
+
if (ctors) {
|
|
1517
|
+
|
|
1518
|
+
// Keep a record of elements that have matched already
|
|
1519
|
+
var matched = $([]), add, rem, res, rule, sel, ctor, dtor;
|
|
1520
|
+
// Stepping through each selector from most to least specific
|
|
1521
|
+
var j = ctors.length;
|
|
1522
|
+
while (j--) {
|
|
1523
|
+
// Build some quick-access variables
|
|
1524
|
+
rule = ctors[j];
|
|
1525
|
+
sel = rule.selector.selector;
|
|
1526
|
+
ctor = rule.onmatch;
|
|
1527
|
+
dtor = rule.onunmatch;
|
|
1528
|
+
|
|
1529
|
+
// Get the list of elements that match this selector, that haven't yet matched a more specific selector
|
|
1530
|
+
res = add = $(sel).not(matched);
|
|
1531
|
+
|
|
1532
|
+
// If this selector has a list of elements it matched against last time
|
|
1533
|
+
if (rule.cache) {
|
|
1534
|
+
// Find the ones that are extra this time
|
|
1535
|
+
add = res.not(rule.cache);
|
|
1536
|
+
if (dtor) {
|
|
1537
|
+
// Find the ones that are gone this time
|
|
1538
|
+
rem = rule.cache.not(res);
|
|
1539
|
+
// And call the destructor on them
|
|
1540
|
+
if (rem.length) ctors.onunmatchproxy(rem, j, dtor);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// Call the constructor on the newly matched ones
|
|
1545
|
+
if (add.length && ctor) ctors.onmatchproxy(add, j, ctor);
|
|
1546
|
+
|
|
1547
|
+
// Add these matched ones to the list tracking all elements matched so far
|
|
1548
|
+
matched = matched.add(res);
|
|
1549
|
+
// And remember this list of matching elements again this selector, so next matching we can find the unmatched ones
|
|
1550
|
+
ctors[j].cache = res;
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
});
|
|
1555
|
+
|
|
1556
|
+
|
|
1557
|
+
})(jQuery);
|
|
1558
|
+
;
|
|
1559
|
+
|
|
1560
|
+
|
|
1561
|
+
/* src/jquery.entwine.properties.js */
|
|
1562
|
+
|
|
1563
|
+
(function($) {
|
|
1564
|
+
|
|
1565
|
+
var entwine_prepend = '__entwine!';
|
|
1566
|
+
|
|
1567
|
+
var getEntwineData = function(el, namespace, property) {
|
|
1568
|
+
return el.data(entwine_prepend + namespace + '!' + property);
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
var setEntwineData = function(el, namespace, property, value) {
|
|
1572
|
+
return el.data(entwine_prepend + namespace + '!' + property, value);
|
|
1573
|
+
};
|
|
1574
|
+
|
|
1575
|
+
var getEntwineDataAsHash = function(el, namespace) {
|
|
1576
|
+
var hash = {};
|
|
1577
|
+
var id = jQuery.data(el[0]);
|
|
1578
|
+
|
|
1579
|
+
var matchstr = entwine_prepend + namespace + '!';
|
|
1580
|
+
var matchlen = matchstr.length;
|
|
1581
|
+
|
|
1582
|
+
var cache = jQuery.cache[id];
|
|
1583
|
+
for (var k in cache) {
|
|
1584
|
+
if (k.substr(0,matchlen) == matchstr) hash[k.substr(matchlen)] = cache[k];
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
return hash;
|
|
1588
|
+
};
|
|
1589
|
+
|
|
1590
|
+
var setEntwineDataFromHash = function(el, namespace, hash) {
|
|
1591
|
+
for (var k in hash) setEntwineData(namespace, k, hash[k]);
|
|
1592
|
+
};
|
|
1593
|
+
|
|
1594
|
+
var entwineData = function(el, namespace, args) {
|
|
1595
|
+
switch (args.length) {
|
|
1596
|
+
case 0:
|
|
1597
|
+
return getEntwineDataAsHash(el, namespace);
|
|
1598
|
+
case 1:
|
|
1599
|
+
if (typeof args[0] == 'string') return getEntwineData(el, namespace, args[0]);
|
|
1600
|
+
else return setEntwineDataFromHash(el, namespace, args[0]);
|
|
1601
|
+
default:
|
|
1602
|
+
return setEntwineData(el, namespace, args[0], args[1]);
|
|
1603
|
+
}
|
|
1604
|
+
};
|
|
1605
|
+
|
|
1606
|
+
$.extend($.fn, {
|
|
1607
|
+
entwineData: function() {
|
|
1608
|
+
return entwineData(this, '__base', arguments);
|
|
1609
|
+
}
|
|
1610
|
+
});
|
|
1611
|
+
|
|
1612
|
+
$.entwine.Namespace.addHandler({
|
|
1613
|
+
order: 60,
|
|
1614
|
+
|
|
1615
|
+
bind: function(selector, k, v) {
|
|
1616
|
+
if (k.charAt(0) != k.charAt(0).toUpperCase()) $.entwine.warn('Entwine property '+k+' does not start with a capital letter', $.entwine.WARN_LEVEL_BESTPRACTISE);
|
|
1617
|
+
|
|
1618
|
+
// Create the getters and setters
|
|
1619
|
+
|
|
1620
|
+
var getterName = 'get'+k;
|
|
1621
|
+
var setterName = 'set'+k;
|
|
1622
|
+
|
|
1623
|
+
this.bind_proxy(selector, getterName, function() { var r = this.entwineData(k); return r === undefined ? v : r; });
|
|
1624
|
+
this.bind_proxy(selector, setterName, function(v){ return this.entwineData(k, v); });
|
|
1625
|
+
|
|
1626
|
+
// Get the get and set proxies we just created
|
|
1627
|
+
|
|
1628
|
+
var getter = this.injectee[getterName];
|
|
1629
|
+
var setter = this.injectee[setterName];
|
|
1630
|
+
|
|
1631
|
+
// And bind in the jQuery-style accessor
|
|
1632
|
+
|
|
1633
|
+
this.bind_proxy(selector, k, function(v){ return (arguments.length == 1 ? setter : getter).call(this, v) ; });
|
|
1634
|
+
|
|
1635
|
+
return true;
|
|
1636
|
+
},
|
|
1637
|
+
|
|
1638
|
+
namespaceMethodOverrides: function(namespace){
|
|
1639
|
+
return {
|
|
1640
|
+
entwineData: function() {
|
|
1641
|
+
return entwineData(this, namespace.name, arguments);
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
})(jQuery);
|
|
1648
|
+
;
|
|
1649
|
+
|
|
1650
|
+
|
|
1651
|
+
/* src/jquery.entwine.legacy.js */
|
|
1652
|
+
|
|
1653
|
+
(function($) {
|
|
1654
|
+
|
|
1655
|
+
// Adds back concrete methods for backwards compatibility
|
|
1656
|
+
$.concrete = $.entwine;
|
|
1657
|
+
$.fn.concrete = $.fn.entwine;
|
|
1658
|
+
$.fn.concreteData = $.fn.entwineData;
|
|
1659
|
+
|
|
1660
|
+
// Use addHandler to hack in the namespace.$.concrete equivilent to the namespace.$.entwine namespace-injection
|
|
1661
|
+
$.entwine.Namespace.addHandler({
|
|
1662
|
+
order: 100,
|
|
1663
|
+
bind: function(selector, k, v) { return false; },
|
|
1664
|
+
|
|
1665
|
+
namespaceMethodOverrides: function(namespace){
|
|
1666
|
+
namespace.$.concrete = namespace.$.entwine;
|
|
1667
|
+
namespace.injectee.concrete = namespace.injectee.entwine;
|
|
1668
|
+
namespace.injectee.concreteData = namespace.injectee.entwineData;
|
|
1669
|
+
return {};
|
|
1670
|
+
}
|
|
1671
|
+
});
|
|
1672
|
+
|
|
1673
|
+
})(jQuery);
|
|
1674
|
+
;
|
|
1675
|
+
|