<commit_before>/**
 * Plugin for a spin-wheel. The kind that can often be found in many mobile OSes natively.
 * Although more simple.
 * Usage:
 * jQuery plugin 'prettySpinner'. See available options from the defaults object in the code.
 * $(el).prettySpinner(options) will return an object with a function called 'liveValue'.
 * liveValue should be passed a callback to be used for listening on changes to the value.
 * The callback will be called every time after the user releases the wheel.
 */
(function ($, undefined) {
	'use strict';

	/**
	 *
	 */
	var SpinView = Backbone.View.extend({

		tagName: 'div',

		className: function () {
			return 'pretty-spinner arrow_box ' + this.options.direction;
		},

		initialize: function (options) {
			this.value = window.isNaN(options.default) ? 0 : options.default;
			this.$el.hammer();

			this.fillWheel();

			this.round();
		},

		fillWheel: function () {
			var container = document.createElement('ul');
			container.className = 'unstyled pretty-spinner-inner';

			var tmpl;
			for (var i = this.options.min; i <= this.options.max; i += this.options.step) {
				tmpl = document.createElement('li');
				tmpl.innerHTML = i;
				tmpl.className = 'pretty-spinner-wheel';
				container.appendChild(tmpl);
			}

			this.$el.append(container);
		},

		render: function () {
			var margin = (-this.value * 30) / this.options.step;
			this.$('.pretty-spinner-wheel:first-child').css('margin-top', margin + 2 * 30);

			return this;
		},

		round: function () {
			this.value = Math.round(this.value / this.options.step) * this.options.step;

			this.model.set('value', this.value);

			this.render();
		},

		events: {
			'dragup': 'spin',
			'dragdown': 'spin',
			'dragend': 'round',
			'click': 'clickSteal'
		},

		clickSteal: function () {
			return false;
		},

		spin: function (e) {
			var gesture = e.gesture;

			var movement = gesture.velocityY * (gesture.direction === 'up' ? 1 : -1);

			this.value += this.options.step * movement;

			if (this.value < this.options.min) {
				this.value = this.options.min;
			}
			if (this.value > this.options.max) {
				this.value = this.options.max;
			}

			this.render();
		}
	});

	/**
	 * Positions the spinner next to the element.
	 */
	var positionSpinner = function (spinView, options) {
		// Append
		spinView.render().$el.appendTo(options.selector || 'body');

		// Position
		var offsetEl = $(options.selector || this);
		var offset = offsetEl.offset() || {};

		if (options.direction === 'right') {
			offset.left += offsetEl.width() + 35;
		} else if (options.direction === 'left') {
			offset.left -= offsetEl.width();
		}

		offset.top -= spinView.$el.outerHeight(true) / 2 - 8;


		spinView.$el.offset(offset);
	};

	// Replace in plugin options object to override these defaults
	var defaults = {
		min: 0,
		max: 100,
		'default': 10,
		step: 0.5,
		direction: 'right'
	};

	/**
	 * Exposed interface. The defaults object above explains possible options.
	 * If options equals 'destroy' the plugin is disabled.
	 */
	$.fn.prettySpinner = function (options) {
		options = $.extend({}, defaults, options);

		var spinModel = new Backbone.Model();

		options.model = spinModel;

		var spinView = new SpinView(options);

		var myPositioner = positionSpinner.bind(this, spinView, options);

		var myRemover = spinView.remove.bind(spinView);

		// Position
		this.bind('focus', myPositioner);

		return {
			liveValue: function liveValue(callback) {
				callback(spinModel.get('value'));

				spinModel.on('change:value', function (model) {
					callback(model.changed.value);
				});
			},
			updatePosition: myPositioner,
			remove: myRemover
		};
	};
}(jQuery));<commit_msg>Spinners now follow focus on the (input)element they're attached to.<commit_after>/**
 * Plugin for a spin-wheel. The kind that can often be found in many mobile OSes natively.
 * Although more simple.
 * Usage:
 * jQuery plugin 'prettySpinner'. See available options from the defaults object in the code.
 * $(el).prettySpinner(options) will return an object with a function called 'liveValue'.
 * liveValue should be passed a callback to be used for listening on changes to the value.
 * The callback will be called every time after the user releases the wheel.
 */
(function ($, undefined) {
	'use strict';

	/**
	 *
	 */
	var SpinView = Backbone.View.extend({

		tagName: 'div',

		className: function () {
			return 'pretty-spinner arrow_box ' + this.options.direction;
		},

		initialize: function (options) {
			this.value = window.isNaN(options.default) ? 0 : options.default;
			this.$el.hammer();

			this.fillWheel();

			this.round();
		},

		fillWheel: function () {
			var container = document.createElement('ul');
			container.className = 'unstyled pretty-spinner-inner';

			var tmpl;
			for (var i = this.options.min; i <= this.options.max; i += this.options.step) {
				tmpl = document.createElement('li');
				tmpl.innerHTML = i;
				tmpl.className = 'pretty-spinner-wheel';
				container.appendChild(tmpl);
			}

			this.$el.append(container);
		},

		render: function () {
			var margin = (-this.value * 30) / this.options.step;
			this.$('.pretty-spinner-wheel:first-child').css('margin-top', margin + 2 * 30);

			return this;
		},

		round: function () {
			this.value = Math.round(this.value / this.options.step) * this.options.step;

			this.model.set('value', this.value);

			this.render();
		},

		events: {
			'dragup': 'spin',
			'dragdown': 'spin',
			'dragend': 'round',
			'touch': 'setActive',
			'release': 'clearActive',
			'click': 'clickSteal'
		},

		setActive: function () {
			this.model.set('active', true);
		},

		clearActive: function () {
			this.model.set('active', false);
		},

		clickSteal: function () {
			return false;
		},

		spin: function (e) {
			var gesture = e.gesture;

			var movement = gesture.velocityY * (gesture.direction === 'up' ? 1 : -1);

			this.value += this.options.step * movement;

			if (this.value < this.options.min) {
				this.value = this.options.min;
			}
			if (this.value > this.options.max) {
				this.value = this.options.max;
			}

			this.render();
		}
	});

	/**
	 * Positions the spinner next to the element.
	 */
	var positionSpinner = function (spinView, options) {
		// Append
		spinView.render().$el.appendTo(options.selector || 'body');

		// Position
		var offsetEl = $(options.selector || this);
		var offset = offsetEl.offset() || {};

		if (options.direction === 'right') {
			offset.left += offsetEl.width() + 35;
		} else if (options.direction === 'left') {
			offset.left -= offsetEl.width();
		}

		offset.top -= spinView.$el.outerHeight(true) / 2 - 8;


		spinView.$el.offset(offset);
	};

	// Replace in plugin options object to override these defaults
	var defaults = {
		min: 0,
		max: 100,
		'default': 10,
		step: 0.5,
		direction: 'right'
	};

	/**
	 * Exposed interface. The defaults object above explains possible options.
	 * If options equals 'destroy' the plugin is disabled.
	 */
	$.fn.prettySpinner = function (options) {
		options = $.extend({}, defaults, options);

		var spinModel = new Backbone.Model();

		options.model = spinModel;

		var spinView = new SpinView(options);

		var myPositioner = positionSpinner.bind(this, spinView, options);

		var myRemover = spinView.remove.bind(spinView);

		// Keep position and visibility updated
		this.bind('focus', myPositioner);
		this.bind('blur', function () {
			setTimeout(function () {
				if (!spinModel.get('active')) {
					spinView.$el.detach();
				}
			}, 100);
		});
		spinModel.on('change:active', function (model) {
			if (model.changed.active === false) {
				this.focus();
			}
		}.bind(this));

		return {
			liveValue: function liveValue(callback) {
				callback(spinModel.get('value'));

				spinModel.on('change:value', function (model) {
					callback(model.changed.value);
				});
			},
			updatePosition: myPositioner,
			remove: myRemover
		};
	};
}(jQuery));
{'fraction_non_alphanumeric': 0.15507684555303602, 'fraction_numerical': 0.005416981607457798, 'mean_word_length': 3.218384697130712, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, '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': '208394', 'n_tokens_mistral': 2970, 'n_tokens_neox': 2491, 'n_words': 651}