2022-02-11 15:48:06 +01:00

197 lines
5.0 KiB
JavaScript

(function(Lazy) {
/**
* A seqence of DOM nodes.
*
* You can get a `DomSequence` by wrapping a `NodeList` or `HTMLCollection`
* with `Lazy`:
*
* var paragraphs = Lazy(document.querySelectorAll('p'));
*
* @public
* @constructor
* @param {NodeList|HTMLCollection} source The underlying collection of DOM
* nodes.
*/
function DomSequence(source) {
this.source = source;
}
DomSequence.prototype = new Lazy.ArrayLikeSequence();
DomSequence.prototype.get = function(i) {
return this.source[i];
};
DomSequence.prototype.length = function() {
return this.source.length;
};
/**
* Provides a sequence comprising all of this sequence's nodes and their
* descendents (children, grandchildren, etc.).
*
* @public
* @returns {Sequence}
*/
DomSequence.prototype.flatten = function() {
return new FlattenedDomSequence(this.source);
};
function FlattenedDomSequence(source) {
this.source = source;
}
FlattenedDomSequence.prototype = new Lazy.Sequence();
FlattenedDomSequence.prototype.each = function(fn) {
var i = 0,
done = false;
Lazy(this.source).each(function(child) {
if (fn(child, i++) === false) {
return false;
}
Lazy(child.children).flatten().each(function(descendent) {
if (fn(descendent, i++) === false) {
done = true;
return false;
}
});
if (done) {
return false;
}
});
};
/**
* Creates a sequence comprising all of the `Event` objects from the given
* event propagating through the node(s) in the current sequence.
*
* @public
* @param {string} eventName The name of the event to catch.
* @returns {AsyncSequence}
*/
DomSequence.prototype.on = function(eventName) {
return new DomEventSequence(this.source, eventName);
};
function DomEventSequence(elements, eventName) {
this.elements = elements;
this.eventName = eventName;
}
DomEventSequence.prototype = new Lazy.Sequence();
/**
* Handles every event in this sequence.
*
* @param {function(Event):*} fn The function to call on each event in the
* sequence. Return false from the function to stop handling the events.
*/
DomEventSequence.prototype.each = function(fn) {
var elements = this.elements,
eventName = this.eventName;
var listener = function(e) {
if (fn(e) === false) {
for (var i = 0; i < elements.length; ++i) {
elements[i].removeEventListener(eventName, listener);
}
}
};
for (var i = 0; i < elements.length; ++i) {
elements[i].addEventListener(this.eventName, listener);
}
};
/**
* Creates a {@link Sequence} from the specified DOM events triggered on the
* given element. This sequence works asynchronously, so synchronous methods
* such as {@code indexOf}, {@code any}, and {@code toArray} won't work.
*
* @param {Element} element The DOM element to capture events from.
* @param {string} eventName The name of the event type (e.g., 'keypress')
* that will make up this sequence.
* @return {Sequence} The sequence of events.
*/
Lazy.events = Lazy.deprecate(
"Lazy.events is deprecated. Use Lazy(element[s]).on('event') instead",
function(element, eventName) {
return new DomEventSequence(element, eventName);
}
);
/**
* A `StreamingHttpSequence` is a {@link StreamLikeSequence} comprising the
* chunks of data that are streamed in response to an HTTP request.
*
* @public
* @param {string} url The URL of the HTTP request.
* @constructor
*/
function StreamingHttpSequence(url) {
this.url = url;
}
StreamingHttpSequence.prototype = new Lazy.StreamLikeSequence();
StreamingHttpSequence.prototype.each = function each(fn) {
var request = new XMLHttpRequest(),
index = 0,
aborted = false;
request.open("GET", this.url);
var handle = new Lazy.AsyncHandle();
var listener = function listener(data) {
if (!aborted) {
data = request.responseText.substring(index);
try {
if (fn(data) === false) {
request.removeEventListener("progress", listener, false);
request.abort();
aborted = true;
handle._resolve(false);
}
index += data.length;
} catch (e) {
handle._reject(e);
}
}
};
request.addEventListener("progress", listener, false);
request.addEventListener("load", function() {
handle._resolve(true);
});
request.send();
return handle;
};
Lazy.makeHttpRequest = function(url) {
return new StreamingHttpSequence(url);
};
/*
* Add support for `Lazy(NodeList)` and `Lazy(HTMLCollection)`.
*/
Lazy.extensions || (Lazy.extensions = []);
Lazy.extensions.push(function(source) {
if (source instanceof NodeList || source instanceof HTMLCollection) {
return new DomSequence(source);
} else if (source instanceof Element) {
return new DomSequence([source]);
}
});
}(window.Lazy));