<commit_before>/*
	Endless: A bidirectional, React infinite scroll component.
	Based on ReactList (https://github.com/orgsync/react-list)
*/

/* global define, module, require, setTimeout, clearTimeout, window */
/* jshint -W116 */ // Don't warn about single-line if's.

(function(root, factory) {
	if (typeof define === 'function' && define.amd) {
		define(['react'], factory);
	} else if (typeof exports !== 'undefined') {
		module.exports = factory(require('react'));
	} else {
		root.Endless = factory(root.React);
	}
})(this, function(React) {
	'use strict';

	var buildReactElement = function(jsonml) {
		if (!Array.isArray(jsonml)) {
			return jsonml;
		}

		if (jsonml.length > 1 &&
			(typeof jsonml[1] !== 'object' || Array.isArray(jsonml[1]))
		) {
			jsonml.splice(1, 0, null);
		}

		return React.createElement.apply(React, jsonml.map(buildReactElement));
	};

	var requestAnimationFrame =
		(typeof window !== 'undefined' && window.requestAnimationFrame) ||
		function(cb) {
			return setTimeout(cb, 16);
		};

	var cancelAnimationFrame =
		(typeof window !== 'undefined' && window.cancelAnimationFrame) ||
		clearTimeout;

	var isEqualSubset = function(a, b) {
		for (var key in a)
			if (b[key] !== a[key]) return false;
		return true;
	};

	var isEqual = function(a, b) {
		return isEqualSubset(a, b) && isEqualSubset(b, a);
	};
	
	var getComputedValue = function (el, propName) {
		var value = parseFloat(window.getComputedStyle(el)[propName]);
		if(isNaN(value)) value = 0;
		return value;
	};

	return React.createClass({
		getDefaultProps: function() {
			return {
				items: [],
				margin: 2000,
				atTop: false,
				atBottom: false,
				onScroll: function( /* key, above, below */ ) {},
				onMount: function( /* event */ ) {},
				onUnmount: function() {}
			};
		},

		getInitialState: function() {
			this.lastState = this.lastState ||  { jumpRequired: true, offset: 0 };
			
			if (this.props.items.length) {
				if (this.props.atTop) {
					this.lastState.jumpToIndex = 0;
					this.lastState.position = 'top';
				} else if (this.props.atBottom) {
					this.lastState.jumpToIndex = this.props.items.length - 1;
					this.lastState.position = 'bottom';
				} else {
					this.lastState.jumpToIndex = 0;
					this.lastState.position = buildReactElement(this.props.items[0]).key;
				}
			}
			
			if (this.props.position) {
				this.lastState.position = this.props.position;
			}

			return {
				itemHeight: 25,
				columns: 1,
				topReached: this.props.atTop,
				bottomReached: this.props.atBottom,
				topRemoved: 0,
				bottomRemoved: 0
			};
		},

		update: function() {
			var items = this.props.items,
				itemsEl = this.refs.items.getDOMNode(),
				itemEls = itemsEl.children,
				jumped = false;
			
			if (!itemEls.length) {
				this.stid = setTimeout(this.update, 200);
				return;
			}
			
			if (this.lastState.jumpRequired && this.lastState.position) {
				if (this.lastState.position == 'top') {
					this.setScroll(-9E99);
				//	this.scrollTo(0, 0);
					jumped = true;
				} else if (this.lastState.position == 'bottom') {
					this.setScroll(9E99);
				//	this.scrollTo(items.length - 1, this.getBottom(itemEls[itemEls.length-1]) - this.getTop(itemEls[itemEls.length-1]));
					jumped = true;
				} else {
					for (i = 0; i < items.length; i++) {
						if (items[i].key == this.lastState.position) {
							this.scrollTo(i, this.lastState.offset);
							jumped = true;
							break;
						}
					}
				}
				
				if(jumped) {
					this.lastState.offset = 0;
					this.lastState.jumpRequired = false;
				}
				
				this.afid = requestAnimationFrame(this.update);
				return;
			}
			
			var viewTop = this.getScroll(),
				viewHeight = this.getViewportHeight(),
				viewBottom = viewTop + viewHeight,
				elBottom = this.getDOMNode().scrollHeight,
				last = this.lastState,
				position, i, offset, above, below, itemHeight, top, columns;
				
			top = this.getTop(itemEls[0]);
			
			for(columns=1; columns<itemEls.length && this.getTop(itemEls[columns]) == top; columns++);
			
			itemHeight = (this.getBottom(itemEls[itemEls.length - 1]) - top) / itemEls.length;
			if(itemHeight <= 0) itemHeight = 20; // Ugly hack for handling display:none items.
			itemHeight *= columns;
						
			if (this.state.bottomReached && !this.state.bottomRemoved && viewBottom >= elBottom-4) {
				position = 'bottom';
				offset = 0;
				above = columns * Math.ceil(viewHeight / itemHeight);
				below = 0;
			} else if (this.state.topReached && !this.state.topRemoved && viewTop <= 4) {
				position = 'top';
				offset = 0;
				above = 0;
				below = columns * Math.ceil(viewHeight / itemHeight);
			} else {
				for (i = 0; i < itemEls.length; i++) {
					offset = itemEls[i].offsetTop + itemEls[i].scrollHeight - viewTop;
					if (offset > 0) break;
				}
				if (i == itemEls.length) i--; // All the items are above the viewport; pick last one.

				position = buildReactElement(items[i]).key; // building in case it is JSONML
				if (viewTop < itemEls[0].offsetTop) {
					offset = viewTop - itemEls[0].offsetTop;
					above = columns * Math.ceil(-offset / itemHeight);
				} else {
					above = 0;
				}
				below = Math.max(0, columns * Math.ceil(Math.max(
					viewHeight, (viewBottom - itemEls[itemEls.length-1].offsetTop)
				) / itemHeight) - above);
			}

			above = Math.round(above);
			below = Math.round(below);

			if (last.position !== position || last.above < above || last.below < below) {
				
//				if(jumped) {
//					console.log(
//						'changing position despite jump',
//						last.position.split('-').pop(),
//						position.split('-').pop(),
//						last.offset, offset,
//						jumpedIndex, i
//					);
//				}
				
				last.position = position;
				last.offset = offset;
				last.above = above;
				last.below = below;
								
				this.afid = requestAnimationFrame(this.update);
				this.props.onScroll(position, above, below);
			} else if(last.offset !== offset) {
				this.afid = requestAnimationFrame(this.update);
			} else {
				this.stid = setTimeout(this.update, 200);
			}
		},<commit_msg>Fixed bug with offsets causing runaway scroll<commit_after>/*
	Endless: A bidirectional, React infinite scroll component.
	Based on ReactList (https://github.com/orgsync/react-list)
*/

/* global define, module, require, setTimeout, clearTimeout, window */
/* jshint -W116 */ // Don't warn about single-line if's.

(function(root, factory) {
	if (typeof define === 'function' && define.amd) {
		define(['react'], factory);
	} else if (typeof exports !== 'undefined') {
		module.exports = factory(require('react'));
	} else {
		root.Endless = factory(root.React);
	}
})(this, function(React) {
	'use strict';

	var buildReactElement = function(jsonml) {
		if (!Array.isArray(jsonml)) {
			return jsonml;
		}

		if (jsonml.length > 1 &&
			(typeof jsonml[1] !== 'object' || Array.isArray(jsonml[1]))
		) {
			jsonml.splice(1, 0, null);
		}

		return React.createElement.apply(React, jsonml.map(buildReactElement));
	};

	var requestAnimationFrame =
		(typeof window !== 'undefined' && window.requestAnimationFrame) ||
		function(cb) {
			return setTimeout(cb, 16);
		};

	var cancelAnimationFrame =
		(typeof window !== 'undefined' && window.cancelAnimationFrame) ||
		clearTimeout;

	var isEqualSubset = function(a, b) {
		for (var key in a)
			if (b[key] !== a[key]) return false;
		return true;
	};

	var isEqual = function(a, b) {
		return isEqualSubset(a, b) && isEqualSubset(b, a);
	};
	
	var getComputedValue = function (el, propName) {
		var value = parseFloat(window.getComputedStyle(el)[propName]);
		if(isNaN(value)) value = 0;
		return value;
	};

	return React.createClass({
		getDefaultProps: function() {
			return {
				items: [],
				margin: 2000,
				atTop: false,
				atBottom: false,
				onScroll: function( /* key, above, below */ ) {},
				onMount: function( /* event */ ) {},
				onUnmount: function() {}
			};
		},

		getInitialState: function() {
			this.lastState = this.lastState ||  { jumpRequired: true, offset: 0 };
			
			if (this.props.items.length) {
				if (this.props.atTop) {
					this.lastState.jumpToIndex = 0;
					this.lastState.position = 'top';
				} else if (this.props.atBottom) {
					this.lastState.jumpToIndex = this.props.items.length - 1;
					this.lastState.position = 'bottom';
				} else {
					this.lastState.jumpToIndex = 0;
					this.lastState.position = buildReactElement(this.props.items[0]).key;
				}
			}
			
			if (this.props.position) {
				this.lastState.position = this.props.position;
			}

			return {
				itemHeight: 25,
				columns: 1,
				topReached: this.props.atTop,
				bottomReached: this.props.atBottom,
				topRemoved: 0,
				bottomRemoved: 0
			};
		},

		update: function() {
			var items = this.props.items,
				itemsEl = this.refs.items.getDOMNode(),
				itemEls = itemsEl.children,
				jumped = false;
			
			if (!itemEls.length) {
				this.stid = setTimeout(this.update, 200);
				return;
			}
			
			if (this.lastState.jumpRequired && this.lastState.position) {
				if (this.lastState.position == 'top') {
					this.setScroll(-9E99);
				//	this.scrollTo(0, 0);
					jumped = true;
				} else if (this.lastState.position == 'bottom') {
					this.setScroll(9E99);
				//	this.scrollTo(items.length - 1, this.getBottom(itemEls[itemEls.length-1]) - this.getTop(itemEls[itemEls.length-1]));
					jumped = true;
				} else {
					for (i = 0; i < items.length; i++) {
						if (items[i].key == this.lastState.position) {
							this.scrollTo(i, this.lastState.offset);
							jumped = true;
							break;
						}
					}
				}
				
				if(jumped) {
					this.lastState.offset = 0;
					this.lastState.jumpRequired = false;
				} else {
					console.log("Endless Error: Jump was required but it did not happen. This usually happens when scrolling down very fast.");
				}
				
				this.afid = requestAnimationFrame(this.update);
				return;
			}
			
			var viewTop = this.getScroll(),
				viewHeight = this.getViewportHeight(),
				viewBottom = viewTop + viewHeight,
				elBottom = this.getDOMNode().scrollHeight,
				last = this.lastState,
				position, i, offset, above, below, itemHeight, top, columns;
				
			top = this.getTop(itemEls[0]);
			
			for(columns=1; columns<itemEls.length && this.getTop(itemEls[columns]) == top; columns++);
			
			itemHeight = (this.getBottom(itemEls[itemEls.length - 1]) - top) / itemEls.length;
			if(itemHeight <= 0) itemHeight = 20; // Ugly hack for handling display:none items.
			itemHeight *= columns;
						
			if (this.state.bottomReached && !this.state.bottomRemoved && viewBottom >= elBottom-4) {
				position = 'bottom';
				offset = 0;
				above = columns * Math.ceil(viewHeight / itemHeight);
				below = 0;
			} else if (this.state.topReached && !this.state.topRemoved && viewTop <= 4) {
				position = 'top';
				offset = 0;
				above = 0;
				below = columns * Math.ceil(viewHeight / itemHeight);
			} else {
				for (i = 0; i < itemEls.length; i++) {
					offset = itemEls[i].offsetTop + itemEls[i].scrollHeight - viewTop;
					if (offset >= 0) {
						offset = viewTop - itemEls[i].offsetTop;
						break;
					}
				}
				if (i == itemEls.length) i--; // All the items are above the viewport; pick last one.

				position = buildReactElement(items[i]).key; // building in case it is JSONML
				if (viewTop < itemEls[0].offsetTop) {
					offset = viewTop - itemEls[0].offsetTop;
					above = columns * Math.ceil(-offset / itemHeight);
				} else {
					above = 0;
				}
				below = Math.max(0, columns * Math.ceil(Math.max(
					viewHeight, (viewBottom - itemEls[itemEls.length-1].offsetTop)
				) / itemHeight) - above);
			}

			above = Math.round(above);
			below = Math.round(below);
			
			if (last.position !== position || last.above < above || last.below < below) {
				
				last.position = position;
				last.offset = offset;
				last.above = above;
				last.below = below;
								
				this.afid = requestAnimationFrame(this.update);
				this.props.onScroll(position, above, below);
			} else if(last.offset !== offset) {
				this.afid = requestAnimationFrame(this.update);
			} else {
				this.stid = setTimeout(this.update, 200);
			}
		},
{'fraction_non_alphanumeric': 0.15166735282009058, 'fraction_numerical': 0.01037463976945245, 'mean_word_length': 2.8730867346938775, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1002838', 'n_tokens_mistral': 5164, 'n_tokens_neox': 4073, 'n_words': 882}