/
protoquery.js
144 lines (114 loc) · 4.06 KB
/
protoquery.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
A fun experiment of "jQuery-way" of performing DOM manipulations
Examples:
// Selects all div elements, adds className 'foo' to them, then selects next elements (nextSibling) after all 'div's and hides them
$Q('div').addClassName('foo').show().next().hide();
// Toggles all div elements with 'collapsible' className when clicked
$Q('div.collapsible').click(function(){ this.toggle() });
// Returned object mixes Enumerable in, so you could always do:
$Q('tr td').invoke('show');
$Q('input[type=text]').pluck('value');
// Certain methods act on a first element only (e.g. #visible, #readAttribute, etc.)
$Q('li a').visible(); // true (checks first element)
// Additional methods are:
#first - returns first element
#last - returns last element
#setProperty(name, value) - sets <name> property to a <value> on all elements
#hover(overHandler, otHandler) - observes mouseover/mouseout events on all elements - invoking overHandler/outHandler functions accordingly
// $Q provides an easy interface for adding additional functionality
// E.g. to simulate jQuery's #width method, we could do something like:
$Q.addMethods({
width: function(value) {
return Object.isUndefined(value)
? this.first().getWidth()
: this.setStyle({ width: value + 'px' });
}
})
*/
(function(){
var Wrapper = Class.create(Enumerable, {
initialize: function(selector) {
this.elements = Object.isString(selector) ? $$(selector) : [selector ? $(selector) : document];
this._toArray();
}
});
function copyFrom(obj) {
for (var method in obj) {
if (/^Simulated|ByTag|classNames|getElementsByClassName|getElementsBySelector|immediateDescendants$/.test(method)) continue;
Wrapper.prototype[method] = (function(method) {
return function() {
var args = $A(arguments), returnFirst = false, result, _elements = [];
this.elements.each(function(element, i) {
result = obj[method].apply(null, args.length ? [element].concat(args) : [element]);
if (Object.isUndefined(result) || !Object.isElement(result)) {
returnFirst = true;
throw $break;
}
result && (_elements[i] = element);
});
if (returnFirst) return result;
this.elements = _elements;
return this;
}
})(method);
};
}
copyFrom(Element.Methods);
copyFrom(Form.Element.Methods);
Wrapper.addMethods({
inspect: function(){
return Object.inspect(this.elements);
},
hover: function(over, out) {
return this.observe('mouseover', function(e) {
over.call(e.target, e);
}).observe('mouseout', function(e) {
out.call(e.target, e);
});
},
setProperty: function(name, value) {
this.each(function(element) {
element[name] = value;
});
return this;
},
_each: function(iterator) {
this.elements._each(iterator);
},
first: function() {
return this.elements[0];
},
last: function() {
return this.elements.last();
},
_toArray: function() {
Array.prototype.push.apply(this, this.elements);
}
});
$w('blur change click dblclick error focus keydown keypress keyup load mousedown ' +
'mousemove mouseout mouseover mouseup resize scroll select submit unload').each(function(eventName) {
Wrapper.prototype[eventName] = (function(eventName) {
return function(handler) {
return this.observe(eventName, handler);
}
})(eventName);
});
this.$Q = function(selector) {
return new Wrapper(selector);
};
this.$Q.addMethods = function(methods) {
for (var name in methods) {
Wrapper.prototype[name] = methods[name];
}
};
Element.addMethods = (function(original) {
var f = function() {
original.apply(original, arguments);
copyFrom(Element.Methods);
copyFrom(Form.Element.Methods);
};
f.toString = original.toString.bind(original);
return f;
})(Element.addMethods);
Element.addMethods();
})();