Skip to content
This repository was archived by the owner on Apr 20, 2018. It is now read-only.

Commit eca216f

Browse files
Adding events
1 parent d550430 commit eca216f

File tree

7 files changed

+333
-147
lines changed

7 files changed

+333
-147
lines changed

src/ajax.js

Lines changed: 54 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -32,116 +32,78 @@
3232
*
3333
* @returns {Observable} An observable sequence containing the XMLHttpRequest.
3434
*/
35-
ajax.ajaxCold = function (settings) {
35+
var ajaxRequest = ajax.ajax = function (settings) {
3636
return new AnonymousObservable(function (observer) {
37-
var isDone = false;
38-
if (typeof settings === 'string') {
39-
settings = { method: 'GET', url: settings, async: true };
40-
}
41-
settings.method || (settings.method = 'GET');
42-
if (settings.async === undefined) {
43-
settings.async = true;
44-
}
37+
var isDone = false;
38+
if (typeof settings === 'string') {
39+
settings = { method: 'GET', url: settings, async: true };
40+
}
41+
settings.method || (settings.method = 'GET');
42+
if (settings.async === undefined) {
43+
settings.async = true;
44+
}
4545

46-
var xhr;
47-
try {
48-
xhr = getXMLHttpRequest();
49-
} catch (err) {
50-
observer.onError(err);
46+
var xhr;
47+
try {
48+
xhr = getXMLHttpRequest();
49+
} catch (err) {
50+
observer.onError(err);
51+
}
52+
53+
try {
54+
if (settings.user) {
55+
xhr.open(settings.method, settings.url, settings.async, settings.user, settings.password);
56+
} else {
57+
xhr.open(settings.method, settings.url, settings.async);
5158
}
5259

53-
try {
54-
if (settings.user) {
55-
xhr.open(settings.method, settings.url, settings.async, settings.user, settings.password);
56-
} else {
57-
xhr.open(settings.method, settings.url, settings.async);
60+
if (settings.headers) {
61+
var headers = settings.headers;
62+
for (var header in headers) {
63+
if (hasOwnProperty.call(headers, header)) {
64+
xhr.setRequestHeader(header, headers[header]);
5865
}
66+
}
67+
}
5968

60-
if (settings.headers) {
61-
var headers = settings.headers;
62-
for (var header in headers) {
63-
if (hasOwnProperty.call(headers, header)) {
64-
xhr.setRequestHeader(header, headers[header]);
65-
}
66-
}
69+
xhr.onreadystatechange = xhr.onload = function () {
70+
if (xhr.readyState === 4) {
71+
var status = xhr.status;
72+
if ((status >= 200 && status <= 300) || status === 0 || status === '') {
73+
observer.onNext(xhr);
74+
observer.onCompleted();
75+
} else {
76+
observer.onError(xhr);
6777
}
6878

69-
xhr.onreadystatechange = xhr.onload = function () {
70-
if (xhr.readyState === 4) {
71-
var status = xhr.status;
72-
if ((status >= 200 && status <= 300) || status === 0 || status === '') {
73-
observer.onNext(xhr);
74-
observer.onCompleted();
75-
} else {
76-
observer.onError(xhr);
77-
}
78-
79-
isDone = true;
80-
}
81-
};
79+
isDone = true;
80+
}
81+
};
8282

83-
xhr.onerror = function () {
84-
observer.onError(xhr);
85-
};
83+
xhr.onerror = function () {
84+
observer.onError(xhr);
85+
};
8686

87-
xhr.send(settings.body || null);
88-
} catch (e) {
89-
observer.onError(e);
90-
}
91-
92-
return disposableCreate( function () {
93-
if (!isDone && xhr.readyState !== 4) {
94-
xhr.abort();
95-
}
96-
});
87+
xhr.send(settings.body || null);
88+
} catch (e) {
89+
observer.onError(e);
90+
}
91+
92+
return function () {
93+
if (!isDone && xhr.readyState !== 4) { xhr.abort(); }
94+
};
9795
});
9896
};
9997

100-
/** @private */
101-
var ajaxCold = ajax.ajaxCold;
102-
103-
/**
104-
* Creates a hot observable for an Ajax request with either a settings object with url, headers, etc or a string for a URL.
105-
*
106-
* @example
107-
* source = Rx.DOM.Request.ajax('/products');
108-
* source = Rx.DOM.Request.ajax( url: 'products', method: 'GET' });
109-
*
110-
* @param {Object} settings Can be one of the following:
111-
*
112-
* A string of the URL to make the Ajax call.
113-
* An object with the following properties
114-
* - url: URL of the request
115-
* - method: Method of the request, such as GET, POST, PUT, PATCH, DELETE
116-
* - async: Whether the request is async
117-
* - headers: Optional headers
118-
*
119-
* @returns {Observable} An observable sequence containing the XMLHttpRequest.
120-
*/
121-
var observableAjax = ajax.ajax = function (settings) {
122-
return ajaxCold(settings).publishLast().refCount();
123-
};
124-
12598
/**
126-
* Creates a cold observable sequence from an Ajax POST Request with the body.
127-
*
128-
* @param {String} url The URL to POST
129-
* @param {Object} body The body to POST
130-
* @returns {Observable} The observable sequence which contains the response from the Ajax POST.
131-
*/
132-
ajax.postCold = function (url, body) {
133-
return observableAjax({ url: url, body: body, method: 'POST', async: true });
134-
};
135-
136-
/**
137-
* Creates a hot observable sequence from an Ajax POST Request with the body.
99+
* Creates an observable sequence from an Ajax POST Request with the body.
138100
*
139101
* @param {String} url The URL to POST
140102
* @param {Object} body The body to POST
141103
* @returns {Observable} The observable sequence which contains the response from the Ajax POST.
142104
*/
143105
ajax.post = function (url, body) {
144-
return observableAjax({ url: url, body: body, method: 'POST', async: true });
106+
return ajaxRequest({ url: url, body: body, method: 'POST', async: true });
145107
};
146108

147109
/**
@@ -151,18 +113,9 @@
151113
* @returns {Observable} The observable sequence which contains the response from the Ajax GET.
152114
*/
153115
var observableGet = ajax.get = function (url) {
154-
return observableAjax({ url: url, method: 'GET', async: true });
116+
return ajaxRequest({ url: url, method: 'GET', async: true });
155117
};
156118

157-
/**
158-
* Creates an observable sequence from an Ajax GET Request with the body.
159-
*
160-
* @param {String} url The URL to GET
161-
* @returns {Observable} The observable sequence which contains the response from the Ajax GET.
162-
*/
163-
var observableGetCold = ajax.getCold = function (url) {
164-
return observableAjax({ url: url, method: 'GET', async: true });
165-
};
166119

167120
if (typeof JSON !== 'undefined' && typeof JSON.parse === 'function') {
168121
/**
@@ -172,19 +125,7 @@
172125
* @returns {Observable} The observable sequence which contains the parsed JSON.
173126
*/
174127
ajax.getJSON = function (url) {
175-
return observableGet(url).select(function (xhr) {
176-
return JSON.parse(xhr.responseText);
177-
});
178-
};
179-
180-
/**
181-
* Creates an observable sequence from JSON from an Ajax request
182-
*
183-
* @param {String} url The URL to GET
184-
* @returns {Observable} The observable sequence which contains the parsed JSON.
185-
*/
186-
ajax.getJSONCold = function (url) {
187-
return observableGetCold(url).select(function (xhr) {
128+
return observableGet(url).map(function (xhr) {
188129
return JSON.parse(xhr.responseText);
189130
});
190131
};

src/events.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
(function () {
2+
var events = "blur focus focusin focusout load resize scroll unload click dblclick " +
3+
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
4+
"change select submit keydown keypress keyup error contextmenu";
5+
6+
if (root.PointerEvent) {
7+
events += " pointerdown pointerup pointermove pointerover pointerout pointerenter pointerleave";
8+
}
9+
10+
events = events.split(' ');
11+
12+
for(var i = 0, len = events.length; i < len; i++) {
13+
var e = events[i];
14+
dom[e] = function (element, selector) {
15+
return fromEvent(element, e, selector);
16+
};
17+
}
18+
}());

src/fromevent.compat.js

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
function fixEvent(event) {
2+
var stopPropagation = function () {
3+
this.cancelBubble = true;
4+
};
5+
6+
var preventDefault = function () {
7+
this.bubbledKeyCode = this.keyCode;
8+
if (this.ctrlKey) {
9+
try {
10+
this.keyCode = 0;
11+
} catch (e) { }
12+
}
13+
this.defaultPrevented = true;
14+
this.returnValue = false;
15+
this.modified = true;
16+
};
17+
18+
event || (event = root.event);
19+
if (!event.target) {
20+
event.target = event.target || event.srcElement;
21+
22+
if (event.type == 'mouseover') {
23+
event.relatedTarget = event.fromElement;
24+
}
25+
if (event.type == 'mouseout') {
26+
event.relatedTarget = event.toElement;
27+
}
28+
// Adding stopPropogation and preventDefault to IE
29+
if (!event.stopPropagation){
30+
event.stopPropagation = stopPropagation;
31+
event.preventDefault = preventDefault;
32+
}
33+
// Normalize key events
34+
switch(event.type){
35+
case 'keypress':
36+
var c = ('charCode' in event ? event.charCode : event.keyCode);
37+
if (c == 10) {
38+
c = 0;
39+
event.keyCode = 13;
40+
} else if (c == 13 || c == 27) {
41+
c = 0;
42+
} else if (c == 3) {
43+
c = 99;
44+
}
45+
event.charCode = c;
46+
event.keyChar = event.charCode ? String.fromCharCode(event.charCode) : '';
47+
break;
48+
}
49+
}
50+
51+
return event;
52+
}
53+
54+
function createListener (element, name, handler) {
55+
// Standards compliant
56+
if (element.addEventListener) {
57+
element.addEventListener(name, handler, false);
58+
return disposableCreate(function () {
59+
element.removeEventListener(name, handler, false);
60+
});
61+
}
62+
if (element.attachEvent) {
63+
// IE Specific
64+
var innerHandler = function (event) {
65+
handler(fixEvent(event));
66+
};
67+
element.attachEvent('on' + name, innerHandler);
68+
return disposableCreate(function () {
69+
element.detachEvent('on' + name, innerHandler);
70+
});
71+
}
72+
// Level 1 DOM Events
73+
element['on' + name] = handler;
74+
return disposableCreate(function () {
75+
element['on' + name] = null;
76+
});
77+
}
78+
79+
function createEventListener (el, eventName, handler) {
80+
var disposables = new CompositeDisposable();
81+
82+
// Asume NodeList
83+
if (Object.prototype.toString.call(el) === '[object NodeList]') {
84+
for (var i = 0, len = el.length; i < len; i++) {
85+
disposables.add(createEventListener(el.item(i), eventName, handler));
86+
}
87+
} else if (el) {
88+
disposables.add(createListener(el, eventName, handler));
89+
}
90+
91+
return disposables;
92+
}
93+
94+
95+
/**
96+
* Creates an observable sequence by adding an event listener to the matching DOMElement or each item in the NodeList.
97+
*
98+
* @example
99+
* var source = Rx.DOM.fromEvent(element, 'mouseup');
100+
*
101+
* @param {Object} element The DOMElement or NodeList to attach a listener.
102+
* @param {String} eventName The event name to attach the observable sequence.
103+
* @param {Function} [selector] A selector which takes the arguments from the event handler to produce a single item to yield on next.
104+
* @returns {Observable} An observable sequence of events from the specified element and the specified event.
105+
*/
106+
var fromEvent = dom.fromEvent = function (element, eventName, selector) {
107+
return new AnonymousObservable(function (observer) {
108+
return createEventListener(
109+
element,
110+
eventName,
111+
function handler (e) {
112+
var results = e;
113+
114+
if (selector) {
115+
try {
116+
results = selector(arguments);
117+
} catch (err) {
118+
observer.onError(err);
119+
return
120+
}
121+
}
122+
123+
observer.onNext(results);
124+
});
125+
}).publish().refCount();
126+
};

0 commit comments

Comments
 (0)