right-rails 1.0.10 → 1.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/README.rdoc +4 -4
  2. data/Rakefile +4 -4
  3. data/lib/right_rails.rb +1 -1
  4. data/public/javascripts/right/autocompleter-src.js +115 -106
  5. data/public/javascripts/right/autocompleter.js +3 -14
  6. data/public/javascripts/right/billboard-src.js +58 -38
  7. data/public/javascripts/right/billboard.js +3 -13
  8. data/public/javascripts/right/calendar-src.js +136 -133
  9. data/public/javascripts/right/calendar.js +4 -33
  10. data/public/javascripts/right/colorpicker-src.js +128 -125
  11. data/public/javascripts/right/colorpicker.js +4 -23
  12. data/public/javascripts/right/dialog-src.js +67 -37
  13. data/public/javascripts/right/dialog.js +3 -17
  14. data/public/javascripts/right/dnd-src.js +44 -43
  15. data/public/javascripts/right/dnd.js +3 -16
  16. data/public/javascripts/right/effects-src.js +125 -98
  17. data/public/javascripts/right/effects.js +3 -13
  18. data/public/javascripts/right/in-edit-src.js +54 -38
  19. data/public/javascripts/right/in-edit.js +4 -10
  20. data/public/javascripts/right/jquerysh-src.js +344 -20
  21. data/public/javascripts/right/jquerysh.js +3 -3
  22. data/public/javascripts/right/json-src.js +22 -35
  23. data/public/javascripts/right/json.js +4 -7
  24. data/public/javascripts/right/keys-src.js +87 -0
  25. data/public/javascripts/right/keys.js +7 -0
  26. data/public/javascripts/right/lightbox-src.js +76 -58
  27. data/public/javascripts/right/lightbox.js +3 -20
  28. data/public/javascripts/right/rails-src.js +108 -107
  29. data/public/javascripts/right/rails.js +4 -11
  30. data/public/javascripts/right/rater-src.js +47 -31
  31. data/public/javascripts/right/rater.js +3 -9
  32. data/public/javascripts/right/resizable-src.js +60 -33
  33. data/public/javascripts/right/resizable.js +3 -11
  34. data/public/javascripts/right/selectable-src.js +87 -51
  35. data/public/javascripts/right/selectable.js +3 -18
  36. data/public/javascripts/right/sizzle-src.js +15 -10
  37. data/public/javascripts/right/sizzle.js +4 -27
  38. data/public/javascripts/right/slider-src.js +49 -33
  39. data/public/javascripts/right/slider.js +3 -10
  40. data/public/javascripts/right/sortable-src.js +46 -32
  41. data/public/javascripts/right/sortable.js +4 -13
  42. data/public/javascripts/right/table-src.js +19 -10
  43. data/public/javascripts/right/table.js +4 -6
  44. data/public/javascripts/right/tabs-src.js +69 -47
  45. data/public/javascripts/right/tabs.js +4 -26
  46. data/public/javascripts/right/tooltips-src.js +78 -56
  47. data/public/javascripts/right/tooltips.js +4 -9
  48. data/public/javascripts/right/uploader-src.js +50 -34
  49. data/public/javascripts/right/uploader.js +3 -9
  50. data/public/javascripts/right-olds-src.js +528 -355
  51. data/public/javascripts/right-olds.js +4 -13
  52. data/public/javascripts/right-safe-src.js +4 -99
  53. data/public/javascripts/right-safe.js +3 -4
  54. data/public/javascripts/right-src.js +1618 -1245
  55. data/public/javascripts/right.js +4 -91
  56. metadata +8 -6
@@ -1,26 +1,29 @@
1
1
  /**
2
- * This is old browsers support patch for RightJS
2
+ * The old browsers support module for RightJS
3
3
  *
4
- * The library released under terms of the MIT license
4
+ * Released under the terms of the MIT license
5
5
  * Visit http://rightjs.org for more details
6
6
  *
7
- * Copyright (C) 2008-2010 Nikolay V. Nemshilov
7
+ * Copyright (C) 2008-2011 Nikolay V. Nemshilov
8
8
  */
9
+ (function(RightJS) {
9
10
  /**
10
11
  * Old IE browser hacks
11
12
  *
12
13
  * Keep them in one place so they were more compact
13
14
  *
14
- * Copyright (C) 2009-2010 Nikolay Nemshilov
15
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
15
16
  */
16
- if (RightJS.Browser.OLD) {
17
+ if (RightJS.Browser.OLD && RightJS.Browser.IE) {
17
18
  // loads DOM element extensions for selected elements
18
- $ = RightJS.$ = (function(old_function) {
19
+ window.$ = RightJS.$ = (function(old_function) {
19
20
  return function(id) {
20
21
  var element = old_function(id);
21
22
 
22
23
  // old IE browses match both, ID and NAME
23
- if (element && element instanceof RightJS.Element && RightJS.isString(id) && element._.id !== id) {
24
+ if (element && element instanceof RightJS.Element &&
25
+ RightJS.isString(id) && element._.id !== id
26
+ ) {
24
27
  element = RightJS.$(document).first('#'+ id);
25
28
  }
26
29
 
@@ -30,17 +33,145 @@ if (RightJS.Browser.OLD) {
30
33
  }
31
34
 
32
35
 
36
+ /**
37
+ * Making the 'submit' and 'change' events bubble under IE browsers
38
+ *
39
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
40
+ */
41
+
42
+ /**
43
+ * Tests if there is the event support
44
+ *
45
+ * @param String event name
46
+ * @retrun Boolean check result
47
+ */
48
+ function event_support_for(name, tag) {
49
+ var e = document.createElement(tag);
50
+ e.setAttribute(name, ';');
51
+ return isFunction(e[name]);
52
+ }
53
+
54
+ if (!event_support_for('onsubmit', 'form')) {
55
+ /**
56
+ * Emulates the 'submit' event bubbling for IE browsers
57
+ *
58
+ * @param raw dom-event
59
+ * @return void
60
+ */
61
+ var submit_boobler = function(raw_event) {
62
+ var event = $(raw_event), element = event.target._,
63
+ type = element.type, form = element.form, parent;
64
+
65
+ if (form && (parent = $(form).parent()) && (
66
+ (raw_event.keyCode === 13 && (type === 'text' || type === 'password')) ||
67
+ (raw_event.type === 'click' && (type === 'submit' || type === 'image'))
68
+ )) {
69
+ event.type = 'submit';
70
+ event.target = $(form);
71
+ parent.fire(event);
72
+ }
73
+ };
74
+
75
+ document.attachEvent('onclick', submit_boobler);
76
+ document.attachEvent('onkeypress', submit_boobler);
77
+ }
78
+
79
+ if (!event_support_for('onchange', 'input')) {
80
+
81
+ var get_input_value = function(target) {
82
+ var element = target._,
83
+ type = element.type;
84
+
85
+ return type === 'radio' || type === 'checkbox' ?
86
+ element.checked : target.getValue();
87
+ },
88
+
89
+ /**
90
+ * Emulates the 'change' event bubbling
91
+ *
92
+ * @param Event wrapped dom-event
93
+ * @param Input wrapped input element
94
+ * @return void
95
+ */
96
+ change_boobler = function(event, target) {
97
+ var parent = target.parent(),
98
+ value = get_input_value(target);
99
+
100
+ if (parent && ''+target._prev_value !== ''+value) {
101
+ target._prev_value = value; // saving the value so it didn't fire up again
102
+ event.type = 'change';
103
+ parent.fire(event);
104
+ }
105
+ },
106
+
107
+ /**
108
+ * Catches the input field changes
109
+ *
110
+ * @param raw dom-event
111
+ * @return void
112
+ */
113
+ catch_inputs_access = function(raw_event) {
114
+ var event = $(raw_event),
115
+ target = event.target,
116
+ type = target._.type,
117
+ tag = target._.tagName,
118
+ input_is_radio = (type === 'radio' || type === 'checkbox');
119
+
120
+ if (
121
+ (event.type === 'click' && (input_is_radio || tag === 'SELECT')) ||
122
+ (event.type === 'keydown' && (
123
+ (event.keyCode == 13 && (tag !== 'TEXTAREA')) ||
124
+ type === 'select-multiple'
125
+ ))
126
+ ) {
127
+ change_boobler(event, target);
128
+ }
129
+ },
130
+
131
+ /**
132
+ * Catch inputs blur
133
+ *
134
+ * @param raw dom-event
135
+ * @return void
136
+ */
137
+ catch_input_left = function(raw_event) {
138
+ var event = $(raw_event),
139
+ target = event.target;
140
+
141
+ if (target instanceof Input) {
142
+ change_boobler(event, target);
143
+ }
144
+ };
145
+
146
+ document.attachEvent('onclick', catch_inputs_access);
147
+ document.attachEvent('onkeydown', catch_inputs_access);
148
+ document.attachEvent('onfocusout', catch_input_left);
149
+
150
+ /**
151
+ * storing the input element previous value, so we could figure out
152
+ * if it was changed later on
153
+ */
154
+ document.attachEvent('onbeforeactivate', function(event) {
155
+ var element = $(event).target;
156
+
157
+ if (element instanceof Input) {
158
+ element._prev_value = get_input_value(element);
159
+ }
160
+ });
161
+ }
162
+
163
+
33
164
  /**
34
165
  * Konqueror browser fixes
35
166
  *
36
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
167
+ * Copyright (C) 2009-2011 Nikolay V. Nemshilov
37
168
  */
38
169
 
39
170
  /**
40
171
  * manual position calculator, it works for Konqueror and also
41
172
  * for old versions of Opera and FF
42
173
  */
43
- if (!RightJS.$E('p').getBoundingClientRect) {
174
+ if (!RightJS.$E('p')._.getBoundingClientRect) {
44
175
  RightJS.Element.include({
45
176
  position: function() {
46
177
  var element = this._,
@@ -68,412 +199,454 @@ if (!RightJS.$E('p').getBoundingClientRect) {
68
199
  * - Sizzle (http://sizzlejs.org) Copyright (C) John Resig
69
200
  * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
70
201
  *
71
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
202
+ * Copyright (C) 2009-2011 Nikolay V. Nemshilov
72
203
  */
73
- if (!document.querySelector) {
74
- (function(RightJS) {
75
- /**
76
- * The token searchers collection
77
- */
78
- var search = {
79
- // search for any descendant nodes
80
- ' ': function(element, tag) {
81
- return RightJS.$A(element.getElementsByTagName(tag));
82
- },
83
-
84
- // search for immidate descendant nodes
85
- '>': function(element, tag) {
86
- var result = [], node = element.firstChild;
87
- while (node) {
88
- if (tag == '*' || node.tagName == tag) {
89
- result.push(node);
90
- }
91
- node = node.nextSibling;
204
+ var has_native_css_selector = !!document.querySelector,
205
+ needs_css_engine_patch = !has_native_css_selector;
206
+
207
+ if (RightJS.Browser.IE8L) {
208
+ needs_css_engine_patch = true;
209
+ }
210
+
211
+ if (needs_css_engine_patch) {
212
+ /**
213
+ * The token searchers collection
214
+ */
215
+ var search = {
216
+ // search for any descendant nodes
217
+ ' ': function(element, tag) {
218
+ return RightJS.$A(element.getElementsByTagName(tag));
219
+ },
220
+
221
+ // search for immidate descendant nodes
222
+ '>': function(element, tag) {
223
+ var result = [], node = element.firstChild;
224
+ while (node) {
225
+ if (tag === '*' || node.tagName === tag) {
226
+ result.push(node);
92
227
  }
93
- return result;
94
- },
95
-
96
- // search for immiate sibling nodes
97
- '+': function(element, tag) {
98
- while ((element = element.nextSibling)) {
99
- if (element.tagName) {
100
- return (tag == '*' || element.tagName == tag) ? [element] : [];
101
- }
228
+ node = node.nextSibling;
229
+ }
230
+ return result;
231
+ },
232
+
233
+ // search for immiate sibling nodes
234
+ '+': function(element, tag) {
235
+ while ((element = element.nextSibling)) {
236
+ if (element.tagName) {
237
+ return (tag === '*' || element.tagName === tag) ? [element] : [];
102
238
  }
103
- return [];
104
- },
105
-
106
- // search for late sibling nodes
107
- '~': function(element, tag) {
108
- var result = [];
109
- while ((element = element.nextSibling)) {
110
- if (tag == '*' || element.tagName == tag) {
111
- result.push(element);
112
- }
239
+ }
240
+ return [];
241
+ },
242
+
243
+ // search for late sibling nodes
244
+ '~': function(element, tag) {
245
+ var result = [];
246
+ while ((element = element.nextSibling)) {
247
+ if (tag === '*' || element.tagName === tag) {
248
+ result.push(element);
113
249
  }
114
- return result;
115
250
  }
116
- };
251
+ return result;
252
+ }
253
+ },
117
254
 
118
255
 
119
- /**
120
- * Collection of pseudo selector matchers
121
- */
122
- var pseudos = {
123
- checked: function() {
124
- return this.checked;
125
- },
256
+ /**
257
+ * Collection of pseudo selector matchers
258
+ */
259
+ pseudos = {
260
+ not: function(node, css_rule) {
261
+ return node.nodeType === 1 && !RightJS.$(node).match(css_rule);
262
+ },
126
263
 
127
- disabled: function() {
128
- return this.disabled;
129
- },
264
+ checked: function(node) {
265
+ return node.checked === true;
266
+ },
130
267
 
131
- empty: function() {
132
- return !(this.innerText || this.innerHTML || this.textContent || '').length;
133
- },
268
+ enabled: function(node) {
269
+ return node.disabled === false;
270
+ },
134
271
 
135
- 'first-child': function(tag_name) {
136
- var node = this;
137
- while ((node = node.previousSibling)) {
138
- if (node.tagName && (!tag_name || node.tagName == tag_name)) {
139
- return false;
140
- }
141
- }
142
- return true;
143
- },
144
-
145
- 'first-of-type': function() {
146
- return arguments[1]['first-child'].call(this, this.tagName);
147
- },
148
-
149
- 'last-child': function(tag_name) {
150
- var node = this;
151
- while ((node = node.nextSibling)) {
152
- if (node.tagName && (!tag_name || node.tagName == tag_name)) {
153
- return false;
154
- }
155
- }
156
- return true;
157
- },
158
-
159
- 'last-of-type': function() {
160
- return arguments[1]['last-child'].call(this, this.tagName);
161
- },
162
-
163
- 'only-child': function(tag_name, matchers) {
164
- return matchers['first-child'].call(this, tag_name) &&
165
- matchers['last-child'].call(this, tag_name);
166
- },
167
-
168
- 'only-of-type': function() {
169
- return arguments[1]['only-child'].call(this, this.tagName, arguments[1]);
170
- },
171
-
172
- 'nth-child': function(number, matchers, tag_name) {
173
- if (!this.parentNode) { return false; }
174
- number = number.toLowerCase();
175
-
176
- if (number == 'n') { return true; }
177
-
178
- if (number.include('n')) {
179
- // parsing out the matching expression
180
- var a = 0, b = 0;
181
- if ((m = number.match(/^([+\-]?\d*)?n([+\-]?\d*)?$/))) {
182
- a = m[1] == '-' ? -1 : parseInt(m[1], 10) || 1;
183
- b = parseInt(m[2], 10) || 0;
184
- }
272
+ disabled: function(node) {
273
+ return node.disabled === true;
274
+ },
185
275
 
186
- // getting the element index
187
- var index = 1, node = this;
188
- while ((node = node.previousSibling)) {
189
- if (node.tagName && (!tag_name || node.tagName == tag_name)) { index++; }
190
- }
276
+ selected: function(node) {
277
+ return node.selected === true;
278
+ },
191
279
 
192
- return (index - b) % a === 0 && (index - b) / a >= 0;
280
+ empty: function(node) {
281
+ return !node.firstChild;
282
+ },
193
283
 
194
- } else {
195
- return matchers.index.call(this, number.toInt() - 1, matchers, tag_name);
284
+ 'first-child': function(node, node_name) {
285
+ while ((node = node.previousSibling)) {
286
+ if (node.nodeType === 1 && (node_name === null || node.nodeName === node_name)) {
287
+ return false;
196
288
  }
197
- },
198
-
199
- 'nth-of-type': function(number) {
200
- return arguments[1]['nth-child'].call(this, number, arguments[1], this.tagName);
201
- },
202
-
203
- // protected
204
- index: function(number, matchers, tag_name) {
205
- number = RightJS.isString(number) ? number.toInt() : number;
206
- var node = this, count = 0;
207
- while ((node = node.previousSibling)) {
208
- if (node.tagName && (!tag_name || node.tagName == tag_name) && ++count > number) { return false; }
209
- }
210
- return count == number;
211
289
  }
212
- };
290
+ return true;
291
+ },
213
292
 
214
- // the regexps collection
215
- var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g;
216
- var id_re = /#([\w\-_]+)/;
217
- var tag_re = /^[\w\*]+/;
218
- var class_re = /\.([\w\-\._]+)/;
219
- var pseudo_re = /:([\w\-]+)(\((.+?)\))*$/;
220
- var attrs_re = /\[((?:[\w\-]*:)?[\w\-]+)\s*(?:([!\^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/;
221
-
222
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
223
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
224
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
225
-
226
- /**
227
- * Builds an atom matcher
228
- *
229
- * @param String atom definition
230
- * @return Object atom matcher
231
- */
232
- var atoms_cache = {};
233
- function build_atom(in_atom) {
234
- if (!atoms_cache[in_atom]) {
235
- var id, tag, classes, attrs, pseudo, values_of_pseudo, match, func, desc = {}, atom = in_atom;
236
-
237
- // grabbing the attributes
238
- while((match = atom.match(attrs_re))) {
239
- attrs = attrs || {};
240
- attrs[match[1]] = { o: match[2], v: match[5] || match[6] };
241
- atom = atom.replace(match[0], '');
242
- }
293
+ 'first-of-type': function(node) {
294
+ return pseudos['first-child'](node, node.nodeName);
295
+ },
243
296
 
244
- // extracting the pseudos
245
- if ((match = atom.match(pseudo_re))) {
246
- pseudo = match[1];
247
- values_of_pseudo = match[3] == '' ? null : match[3];
248
- atom = atom.replace(match[0], '');
297
+ 'last-child': function(node, node_name) {
298
+ while ((node = node.nextSibling)) {
299
+ if (node.nodeType === 1 && (node_name === null || node.nodeName === node_name)) {
300
+ return false;
249
301
  }
302
+ }
303
+ return true;
304
+ },
250
305
 
251
- // getting all the other options
252
- id = (atom.match(id_re) || [1, null])[1];
253
- tag = (atom.match(tag_re) || '*').toString().toUpperCase();
254
- classes = (atom.match(class_re) || [1, ''])[1].split('.').without('');
255
-
256
- desc.tag = tag;
257
-
258
- //
259
- // HACK HACK HACK
260
- //
261
- // building the matcher function
262
- //
263
- // NOTE: we kinda compile a cutom filter function in here
264
- // the point is to create a maximally optimized method
265
- // that will make only this atom checks and will filter
266
- // a list of elements in a single call
267
- //
268
- if (id || classes.length || attrs || pseudo) {
269
- var filter = 'function(y){'+
270
- 'var e,r=[],z=0,x=y.length;'+
271
- 'for(;z<x;z++){'+
272
- 'e=y[z];_f_'+
273
- '}return r}';
274
-
275
- var patch_filter = function(code) {
276
- filter = filter.replace('_f_', code + '_f_');
277
- };
278
-
279
- // adding the ID check conditions
280
- if (id) { patch_filter('if(e.id!=i)continue;'); }
281
-
282
- // adding the classes matching code
283
- if (classes.length) { patch_filter(
284
- 'if(e.className){'+
285
- 'var n=e.className.split(" ");'+
286
- 'if(n.length==1&&c.indexOf(n[0])==-1)continue;'+
287
- 'else{'+
288
- 'for(var i=0,l=c.length,b=false;i<l;i++)'+
289
- 'if(n.indexOf(c[i])==-1){'+
290
- 'b=true;break;}'+
291
-
292
- 'if(b)continue;}'+
293
- '}else continue;'
294
- ); }
295
-
296
- // adding the attributes matching conditions
297
- if (attrs) { patch_filter(
298
- 'var p,o,v,k,b=false;'+
299
- 'for (k in a){p=e.getAttribute(k)||"";o=a[k].o||"";v=a[k].v||"";'+
300
- 'if('+
301
- '(o===""&&e.getAttributeNode(k)===null)||'+
302
- '(o==="="&&p!=v)||'+
303
- '(o==="*="&&!p.include(v))||'+
304
- '(o==="^="&&!p.startsWith(v))||'+
305
- '(o==="$="&&!p.endsWith(v))||'+
306
- '(o==="~="&&!p.split(" ").include(v))||'+
307
- '(o==="|="&&!p.split("-").include(v))'+
308
- '){b=true;break;}'+
309
- '}if(b){continue;}'
310
- ); }
311
-
312
- // adding the pseudo matchers check
313
- if (pseudo in pseudos) {
314
- patch_filter('if(!S[P].call(e,V,S))continue;');
315
- }
306
+ 'last-of-type': function(node) {
307
+ return pseudos['last-child'](node, node.nodeName);
308
+ },
316
309
 
317
- //
318
- // HACK HACK HACK
319
- //
320
- // Here we separate the names space from the outside
321
- // and inside of the function, so that when this thing
322
- // is optimized by the code compiler, it kept the necessary
323
- // variable names intackt
324
- //
325
- desc.filter = eval(
326
- "[function(i,t,c,a,P,V,S,s){return eval('['+s+']')[0]}]"
327
- )[0](
328
- id,tag,classes,attrs,pseudo,values_of_pseudo,pseudos,
329
- filter.replace('_f_', 'r.push(e)')
330
- );
331
- }
310
+ 'only-child': function(node, node_name) {
311
+ return pseudos['first-child'](node, node_name) &&
312
+ pseudos['last-child'](node, node_name);
313
+ },
332
314
 
333
- atoms_cache[in_atom] = desc;
334
- }
315
+ 'only-of-type': function(node) {
316
+ return pseudos['only-child'](node, node.nodeName);
317
+ },
335
318
 
336
- return atoms_cache[in_atom];
337
- }
319
+ 'nth-child': function(node, number, node_name, reverse) {
320
+ var index = 1, a = number[0], b = number[1];
338
321
 
339
- /**
340
- * Builds a single selector out of a simple rule chunk
341
- *
342
- * @param Array of a single rule tokens
343
- * @return Function selector
344
- */
345
- var tokens_cache = {};
346
- function build_selector(rule) {
347
- var rule_key = rule.join('');
348
- if (!tokens_cache[rule_key]) {
349
- for (var i=0; i < rule.length; i++) {
350
- rule[i][1] = build_atom(rule[i][1]);
322
+ while ((node = (reverse === true) ? node.nextSibling : node.previousSibling)) {
323
+ if (node.nodeType === 1 && (node_name === undefined || node.nodeName === node_name)) {
324
+ index++;
351
325
  }
326
+ }
352
327
 
353
- // creates a list of uniq nodes
354
- var _uid = $uid;
355
- var uniq = function(elements) {
356
- var uniq = [], uids = [], uid;
357
- for (var i=0, length = elements.length; i < length; i++) {
358
- uid = _uid(elements[i]);
359
- if (!uids[uid]) {
360
- uniq.push(elements[i]);
361
- uids[uid] = true;
362
- }
363
- }
328
+ return (b === undefined ? (index === a) : ((index - b) % a === 0 && (index - b) / a >= 0));
329
+ },
364
330
 
365
- return uniq;
366
- };
331
+ 'nth-of-type': function(node, number) {
332
+ return pseudos['nth-child'](node, number, node.nodeName);
333
+ },
367
334
 
368
- // performs the actual search of subnodes
369
- var find_subnodes = function(element, atom) {
370
- var result = search[atom[0]](element, atom[1].tag);
371
- return atom[1].filter ? atom[1].filter(result) : result;
372
- };
335
+ 'nth-last-child': function(node, number) {
336
+ return pseudos['nth-child'](node, number, undefined, true);
337
+ },
373
338
 
374
- // building the actual selector function
375
- tokens_cache[rule_key] = function(element) {
376
- var founds, sub_founds;
339
+ 'nth-last-of-type': function(node, number) {
340
+ return pseudos['nth-child'](node, number, node.nodeName, true);
341
+ }
342
+ },
343
+
344
+ // the regexps collection
345
+ chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
346
+ id_re = /#([\w\-_]+)/,
347
+ tag_re = /^[\w\*]+/,
348
+ class_re = /\.([\w\-\._]+)/,
349
+ pseudo_re = /:([\w\-]+)(\((.+?)\))*$/,
350
+ attrs_re = /\[((?:[\w\-]*:)?[\w\-]+)\s*(?:([!\^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/,
351
+
352
+ ///////////////////////////////////////////////////////////////////////////////
353
+ ///////////////////////////////////////////////////////////////////////////////
354
+ ///////////////////////////////////////////////////////////////////////////////
355
+
356
+ /**
357
+ * Builds an atom matcher
358
+ *
359
+ * @param String atom definition
360
+ * @return Object atom matcher
361
+ */
362
+ atoms_cache = {},
363
+ build_atom = function(in_atom) {
364
+ if (!atoms_cache[in_atom]) {
365
+ var id, tag, classes, classes_length, attrs, pseudo,
366
+ values_of_pseudo, match, func, desc = {}, atom = in_atom;
367
+
368
+ // grabbing the attributes
369
+ while((match = atom.match(attrs_re))) {
370
+ attrs = attrs || {};
371
+ attrs[match[1]] = { o: match[2] || '', v: match[5] || match[6] || '' };
372
+ atom = atom.replace(match[0], '');
373
+ }
374
+
375
+ // extracting the pseudos
376
+ if ((match = atom.match(pseudo_re))) {
377
+ pseudo = match[1];
378
+ values_of_pseudo = match[3] === '' ? null : match[3];
377
379
 
378
- for (var i=0, i_length = rule.length; i < i_length; i++) {
379
- if (i === 0) {
380
- founds = find_subnodes(element, rule[i]);
380
+ if (pseudo.startsWith('nth')) {
381
+ // preparsing the nth-child pseoudo numbers
382
+ values_of_pseudo = values_of_pseudo.toLowerCase();
381
383
 
384
+ if (values_of_pseudo === 'n') {
385
+ // no need in the pseudo then
386
+ pseudo = null;
387
+ values_of_pseudo = null;
388
+ } else {
389
+ if (values_of_pseudo === 'odd') { values_of_pseudo = '2n+1'; }
390
+ if (values_of_pseudo === 'even') { values_of_pseudo = '2n'; }
391
+
392
+ var m = /^([+\-]?\d*)?n([+\-]?\d*)?$/.exec(values_of_pseudo);
393
+ if (m) {
394
+ values_of_pseudo = [
395
+ m[1] === '-' ? -1 : parseInt(m[1], 10) || 1,
396
+ parseInt(m[2], 10) || 0
397
+ ];
382
398
  } else {
383
- if (i > 1) { founds = uniq(founds); }
399
+ values_of_pseudo = [parseInt(values_of_pseudo, 10), undefined];
400
+ }
401
+ }
402
+ }
403
+
404
+ atom = atom.replace(match[0], '');
405
+ }
406
+
407
+ // getting all the other options
408
+ id = (atom.match(id_re) || [1, null])[1];
409
+ tag = (atom.match(tag_re) || '*').toString().toUpperCase();
410
+ classes = (atom.match(class_re) || [1, ''])[1].split('.').without('');
411
+ classes_length = classes.length;
412
+
413
+ desc.tag = tag;
414
+
415
+ if (id || classes.length || attrs || pseudo) {
416
+ // optimizing a bit the values for quiker runtime checks
417
+ id = id || false;
418
+ attrs = attrs || false;
419
+ pseudo = pseudo in pseudos ? pseudos[pseudo] : false;
420
+ classes = classes_length ? classes : false;
421
+
422
+ desc.filter = function(elements) {
423
+ var node, result = [], i=0, j=0, l = elements.length, failed;
424
+ for (; i < l; i++) {
425
+ node = elements[i];
426
+
427
+ //////////////////////////////////////////////
428
+ // ID check
429
+ //
430
+ if (id !== false && node.id !== id) {
431
+ continue;
432
+ }
433
+
434
+ //////////////////////////////////////////////
435
+ // Class names check
436
+ if (classes !== false) {
437
+ var names = node.className.split(' '),
438
+ names_length = names.length,
439
+ x = 0; failed = false;
440
+
441
+ for (; x < classes_length; x++) {
442
+ for (var y=0, found = false; y < names_length; y++) {
443
+ if (classes[x] === names[y]) {
444
+ found = true;
445
+ break;
446
+ }
447
+ }
448
+
449
+ if (!found) {
450
+ failed = true;
451
+ break;
452
+ }
453
+ }
384
454
 
385
- for (var j=0; j < founds.length; j++) {
386
- sub_founds = find_subnodes(founds[j], rule[i]);
455
+ if (failed) { continue; }
456
+ }
387
457
 
388
- sub_founds.unshift(1); // <- nuke the parent node out of the list
389
- sub_founds.unshift(j); // <- position to insert the subresult
458
+ ///////////////////////////////////////////////
459
+ // Attributes check
460
+ if (attrs !== false) {
461
+ var key, attr, operand, value; failed = false;
462
+ for (key in attrs) {
463
+ attr = key === 'class' ? node.className : (node.getAttribute(key) || '');
464
+ operand = attrs[key].o;
465
+ value = attrs[key].v;
466
+
467
+ if (
468
+ (operand === '' && (key === 'class'|| key === 'lang' ?
469
+ (attr === '') : (node.getAttributeNode(key) === null))) ||
470
+ (operand === '=' && attr !== value) ||
471
+ (operand === '*=' && attr.indexOf(value) === -1) ||
472
+ (operand === '^=' && attr.indexOf(value) !== 0) ||
473
+ (operand === '$=' && attr.substring(attr.length - value.length) !== value) ||
474
+ (operand === '~=' && attr.split(' ').indexOf(value) === -1) ||
475
+ (operand === '|=' && attr.split('-').indexOf(value) === -1)
476
+ ) { failed = true; break; }
477
+ }
390
478
 
391
- founds.splice.apply(founds, sub_founds);
479
+ if (failed) { continue; }
480
+ }
392
481
 
393
- j += sub_founds.length - 3;
482
+ ///////////////////////////////////////////////
483
+ // Pseudo selectors check
484
+ if (pseudo !== false) {
485
+ if (!pseudo(node, values_of_pseudo)) {
486
+ continue;
394
487
  }
395
488
  }
396
- }
397
489
 
398
- return rule.length > 1 ? uniq(founds) : founds;
490
+ result[j++] = node;
491
+ }
492
+ return result;
399
493
  };
400
494
  }
401
- return tokens_cache[rule_key];
495
+
496
+ atoms_cache[in_atom] = desc;
402
497
  }
403
498
 
499
+ return atoms_cache[in_atom];
500
+ },
501
+
502
+ /**
503
+ * Builds a single selector out of a simple rule chunk
504
+ *
505
+ * @param Array of a single rule tokens
506
+ * @return Function selector
507
+ */
508
+ tokens_cache = {},
509
+ build_selector = function(rule) {
510
+ var rule_key = rule.join('');
511
+ if (!tokens_cache[rule_key]) {
512
+ for (var i=0; i < rule.length; i++) {
513
+ rule[i][1] = build_atom(rule[i][1]);
514
+ }
515
+
516
+ // creates a list of uniq nodes
517
+ var _uid = RightJS.$uid;
518
+ var uniq = function(elements) {
519
+ var uniq = [], uids = [], uid;
520
+ for (var i=0, length = elements.length; i < length; i++) {
521
+ uid = _uid(elements[i]);
522
+ if (!uids[uid]) {
523
+ uniq.push(elements[i]);
524
+ uids[uid] = true;
525
+ }
526
+ }
527
+
528
+ return uniq;
529
+ };
404
530
 
405
- /**
406
- * Builds the list of selectors for the css_rule
407
- *
408
- * @param String raw css-rule
409
- * @return Array of selectors
410
- */
411
- var selectors_cache = {}, chunks_cache = {};
412
- function split_rule_to_selectors(css_rule) {
413
- if (!selectors_cache[css_rule]) {
414
- chunker.lastIndex = 0;
531
+ // performs the actual search of subnodes
532
+ var find_subnodes = function(element, atom) {
533
+ var result = search[atom[0]](element, atom[1].tag);
534
+ return atom[1].filter ? atom[1].filter(result) : result;
535
+ };
415
536
 
416
- var rules = [], rule = [], rel = ' ', m, token;
417
- while ((m = chunker.exec(css_rule))) {
418
- token = m[1];
537
+ // building the actual selector function
538
+ tokens_cache[rule_key] = function(element) {
539
+ var founds, sub_founds;
540
+
541
+ for (var i=0, i_length = rule.length; i < i_length; i++) {
542
+ if (i === 0) {
543
+ founds = find_subnodes(element, rule[i]);
419
544
 
420
- if (token == '+' || token == '>' || token == '~') {
421
- rel = token;
422
545
  } else {
423
- rule.push([rel, token]);
424
- rel = ' ';
425
- }
546
+ if (i > 1) { founds = uniq(founds); }
547
+
548
+ for (var j=0; j < founds.length; j++) {
549
+ sub_founds = find_subnodes(founds[j], rule[i]);
426
550
 
427
- if (m[2]) {
428
- rules.push(build_selector(rule));
429
- rule = [];
551
+ sub_founds.unshift(1); // <- nuke the parent node out of the list
552
+ sub_founds.unshift(j); // <- position to insert the subresult
553
+
554
+ founds.splice.apply(founds, sub_founds);
555
+
556
+ j += sub_founds.length - 3;
557
+ }
430
558
  }
431
559
  }
432
- rules.push(build_selector(rule));
433
560
 
434
- selectors_cache[css_rule] = rules;
435
- }
436
- return selectors_cache[css_rule];
561
+ return rule.length > 1 ? uniq(founds) : founds;
562
+ };
437
563
  }
564
+ return tokens_cache[rule_key];
565
+ },
566
+
567
+
568
+ /**
569
+ * Builds the list of selectors for the css_rule
570
+ *
571
+ * @param String raw css-rule
572
+ * @return Array of selectors
573
+ */
574
+ selectors_cache = {}, chunks_cache = {},
575
+ split_rule_to_selectors = function(css_rule) {
576
+ if (!selectors_cache[css_rule]) {
577
+ chunker.lastIndex = 0;
578
+
579
+ var rules = [], rule = [], rel = ' ', m, token;
580
+ while ((m = chunker.exec(css_rule))) {
581
+ token = m[1];
582
+
583
+ if (token === '+' || token === '>' || token === '~') {
584
+ rel = token;
585
+ } else {
586
+ rule.push([rel, token]);
587
+ rel = ' ';
588
+ }
438
589
 
439
-
440
- /**
441
- * The top level method, it just goes throught the css-rule chunks
442
- * collect and merge the results that's it
443
- *
444
- * @param Element context
445
- * @param String raw css-rule
446
- * @return Array search result
447
- */
448
- function select_all(element, css_rule) {
449
- var selectors = split_rule_to_selectors(css_rule), result = [];
450
- for (var i=0, length = selectors.length; i < length; i++) {
451
- result = result.concat(selectors[i](element));
590
+ if (m[2]) {
591
+ rules.push(build_selector(rule));
592
+ rule = [];
593
+ }
452
594
  }
595
+ rules.push(build_selector(rule));
453
596
 
454
- return result;
597
+ selectors_cache[css_rule] = rules;
455
598
  }
599
+ return selectors_cache[css_rule];
600
+ },
601
+
602
+
603
+ /**
604
+ * The top level method, it just goes throught the css-rule chunks
605
+ * collect and merge the results that's it
606
+ *
607
+ * @param Element context
608
+ * @param String raw css-rule
609
+ * @return Array search result
610
+ */
611
+ select_all = function(element, css_rule) {
612
+ var selectors = split_rule_to_selectors(css_rule), result = [];
613
+ for (var i=0, length = selectors.length; i < length; i++) {
614
+ result = result.concat(selectors[i](element));
615
+ }
616
+
617
+ return result;
618
+ },
619
+
456
620
 
621
+ ///////////////////////////////////////////////////////////////////////////////
622
+ ///////////////////////////////////////////////////////////////////////////////
623
+ ///////////////////////////////////////////////////////////////////////////////
457
624
 
458
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
459
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
460
- /////////////////////////////////////////////////////////////////////////////////////////////////////////
625
+ // the previous dom-selection methods replacement
626
+ dom_extension = {
627
+ first: function(css_rule) {
628
+ return this.find(css_rule)[0];
629
+ },
461
630
 
462
- // the previous dom-selection methods replacement
463
- var dom_extension = {
464
- first: function(css_rule) {
465
- return this.find(css_rule)[0];
466
- },
631
+ find: function(css_rule, raw) {
632
+ var result, rule = css_rule || '*', element = this._, tag = element.tagName;
467
633
 
468
- find: function(css_rule) {
469
- return select_all(this._, css_rule || '*').map(RightJS.$);
634
+ if (has_native_css_selector) {
635
+ try { // trying to reuse native css-engine under IE8
636
+ result = $A(element.querySelectorAll(rule));
637
+ } catch(e) { // if it fails use our own engine
638
+ result = select_all(element, rule);
639
+ }
640
+ } else {
641
+ result = select_all(element, rule);
470
642
  }
471
- };
472
643
 
473
- dom_extension.select = dom_extension.find;
644
+ return raw === true ? result : result.map(RightJS.$);
645
+ }
646
+ };
474
647
 
475
- // hooking up the rightjs wrappers with the new methods
476
- RightJS.Element.include(dom_extension);
477
- RightJS.Document.include(dom_extension);
478
- })(RightJS);
648
+ // hooking up the rightjs wrappers with the new methods
649
+ RightJS.$ext(RightJS.Element.prototype, dom_extension);
650
+ RightJS.$ext(RightJS.Document.prototype, dom_extension);
479
651
  }
652
+ })(RightJS);