right-rails 1.0.10 → 1.0.12

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.
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);