<commit_before>AUI().add(
	'data-set',
	function(A) {
		var Lang = A.Lang;

		var DataSet = function() {
			DataSet.superclass.constructor.apply(this, arguments);
		};

		DataSet.NAME = 'compoundset';

		DataSet.ATTRS = {
			keys: {
				getter: function(value) {
					var instance = this;

					return A.Object.keys(instance.collection);
				}
			},

			first: {
				getter: function() {
					var instance = this;

					var values = instance.values;

					return values[0];
				}
			},

			includeFunctions: {
				value: false
			},

			items: {
				value: null,
				getter: function() {
					var instance = this;

					return instance.collection || {};
				}
			},

			last: {
				getter: function() {
					var instance = this;

					var values = instance.values;

					return values[values.length - 1];
				}
			},

			getKey: {
				lazyAdd: false,
				value: null,
				getter: function(value) {
					var instance = this;

					return value || instance.getKey;
				},
				setter: function(value) {
					var instance = this;

					if (Lang.isFunction(value)) {
						instance.getKey = value;
					}

					return instance.getKey;
				}
			},

			values: {
				getter: function(value) {
					var instance = this;

					return instance.values;
				},
				readOnly: true
			}
		};

		A.extend(
			DataSet,
			A.Base,
			{
				initializer: function() {
					var instance = this;

					instance.collection = {};
					instance.values = [];

					instance.length = 0;
				},

				add: function(key, obj) {
					var instance = this;

					if (arguments.length == 1) {
						obj = key;
						key = instance.getKey(obj);
					}

					var includeFunctions = instance.get('includeFunctions');

					if (!Lang.isNull(key) && !Lang.isUndefined(key)) {
						var prevVal = instance.collection[key];

						if (!Lang.isUndefined(prevVal)) {
							return instance.replace(key, obj);
						}

						if (includeFunctions || !Lang.isFunction(obj)) {
							instance.collection[key] = obj;
						}
					}

					instance.values.push(obj);

					instance.fire(
						'add',
						{
							index: instance.length,
							attrName: key,
							newVal: obj
						}
					);

					instance.length++;
				},

				addAll: function(obj) {
					var instance = this;

					var args = arguments;
					var length = args.length;

					if (length == 1) {
						args = obj;
					}

					if (length > 1 || Lang.isArray(obj)) {
						length = args.length;

						for (var i = 0; i < length; i++) {
							instance.add(args[i]);
						}
					}
					else {
						for (var i in obj) {
							var item = obj[i];

							instance.add(i, item);
						}
					}
				},

				clear: function() {
					var instance = this;

					instance.collection = {};
					instance.values = [];
					instance.length = 0;

					instance.fire('clear');
				},

				clone: function() {
					var instance = this;

					var clone = new DataSet();

					clone._collection = A.Object(instance.collection);
					clone.length = instance.length;
					clone.set('getKey', instance.get('getKey'));

					return clone;
				},

				contains: function(obj) {
					var instance = this;

					return instance.indexOf(obj) > -1;
				},

				containsKey: function(key) {
					var instance = this;

					return !(Lang.isUndefined(instance.collection[key]))
				},

				each: function(fn, context) {
					var instance = this;

					return instance._each(instance.values, fn, context);
				},

				eachKey: function(fn, context) {
					var instance = this;

					var keys = instance.get('keys');

					return instance._each(keys, fn, context);
				},

				filter: function(fn, context) {
					var instance = this;

					var filtered = new DataSet();

					filtered.set('getKey', instance.get('getKey'));

					var collection = instance.collection;
					var keys = instance.get('keys');
					var values = instance.values;

					context = context || instance;

					var filteredDataSet = filtered.collection;
					var filteredValues = filtered.values;

					var length = values.length;
					var item;

					for (var i = 0; i < length; i++) {
						item = values[i];

						if (fn.call(context, item, i, collection)) {
							filtered.add(keys[i], item);
						}
					}

					filtered.length = filteredValues.length;

					return filtered;
				},

				filterBy: function(key, value, startsWith, caseSensitive) {
					var instance = this;

					if (Lang.isUndefined(value) ||
					 	Lang.isNull(value) ||
						((Lang.isArray(value) ||
							Lang.isString(value)) && !value.length)) {

						return instance.clone();
					}

					value = instance._generateRegEx(value, startsWith, caseSensitive);

					var keyFilter = A.bind(instance._keyFilter, instance, key, value);

					return instance.filter(keyFilter);
				},

				find: function(fn, context) {
					var instance = this;

					return A.Array.find(instance.values, fn, context);
				},

				findIndex: function(fn, context, start) {
					var instance = this;

					var collection = instance.collection;
					var values = instance.values;
					var length = instance.length;

					start = start || 0;

					for (var i = start; i < length; i++) {
						if (fn.call(context, values[i], i, collection)) {
							return i;
						}
					}

					return -1;
				},

				findIndexBy: function(key, value, start, startsWith, caseSensitive) {
					var instance = this;

					if (Lang.isUndefined(value) ||
					 	Lang.isNull(value) ||
						((Lang.isArray(value) ||
							Lang.isString(value)) && !value.length)) {

						return -1;
					}

					value = instance._generateRegEx(value, startsWith, caseSensitive);

					var keyFilter = A.bind(instance._keyFilter, instance, key, value);

					return instance.findIndex(keyFilter, null, start);
				},

				getKey: function(obj) {
					var instance = this;

					return (obj.get && obj.get('id')) || obj.id;
				},

				indexOf: function(obj) {
					var instance = this;

					var values = instance.values;

					return A.Array.indexOf(values, obj);
				},

				indexOfKey: function(key) {
					var instance = this;

					var keys = instance.get('keys');

					return A.Array.indexOf(keys, key);
				},

				insert: function(index, key, obj) {
					var instance = this;

					if (arguments.length == 2) {
						obj = arguments[1];
						key = instance.getKey(obj);
					}

					if (instance.containsKey(key)) {
						instance.removeKey(key);
					}

					if (index >= instance.length) {
						return instance.add(key, obj);
					}

					instance.values.splice(index, 0, obj);

					instance.length++;

					if (!Lang.isUndefined(key) && !Lang.isNull(key)) {
						instance.collection[key] = obj;
					}

					instance.fire(
						'add',
						{
							index: instance.length,
							attrName: key,
							newVal: obj
						}
					);
				},

				invoke: function(method, args) {
					var instance = this;

					var values = instance.values;
					var length = values.length;

					if (!args) {
						args = [];
					}
					else {
						args = [].concat(args);
					}

					for (var i = 0; i < length; i++) {
						var item = values[i];
						var itemMethod = item && item[method];

						if (Lang.isFunction(itemMethod)) {
							itemMethod.apply(item, args);
						}
					}

					return instance;
				},

				item: function(key) {
					var instance = this;

					var item;

					if (Lang.isNumber(key)) {
						var values = instance.values;

						item = values[key];
					}
					else {
						item = instance.collection[key];
					}

					return item;
				},

				keySort: function(direction, fn) {
					var instance = this;

					instance._sortBy('key', direction, fn || instance._keySorter);
				},

				remove: function(obj) {
					var instance = this;

					var index = instance.indexOf(obj);

					return instance.removeAt(index);
				},

				removeAt: function(index) {
					var instance = this;

					if (index < instance.length && index >= 0) {
						var collection = instance.collection;
						var values = instance.values;

						var obj = values[index];

						values.splice(index, 1);

						var keys = instance.get('keys');
						var key = keys[index];

						if (!Lang.isUndefined(key)) {
							delete collection[key];
						}

						instance.length--;
					}
				},

				removeKey: function(key) {
					var instance = this;

					var index = instance.indexOfKey(key);

					return instance.removeAt(index);
				},

				replace: function(key, obj) {
					var instance = this;

					if (arguments.length == 1) {
						obj = key;
						key = instance.getKey(obj);
					}

					var prevVal = instance.collection[key];

					if (Lang.isUndefined(key) || Lang.isNull(key) || Lang.isUndefined(prevVal)) {
						return instance.add(key, obj);
					}

					var index = instance.indexOfKey(key);

					instance.collection[key] = obj;

					instance.fire(
						'replace',
						{
							attrName: key,
							prevVal: prevVal,
							newVal: obj
						}
					);
				},

				size: function() {
					var instance = this;

					return instance.length;
				},

				slice: function(start, end) {
					var instance = this;

					var values = instance.values;

					return values.slice.apply(values, arguments);
				},

				sort: function(direction, fn) {
					var instance = this;

					instance._sortBy('value', direction, fn);
				},

				_each: function(arr, fn, context) {
					var instance = this;

					var length = arr.length;

					context = context || instance;

					for (var i = 0; i < length; i++) {
						if (fn.call(context, arr[i], i, arr) === false) {
							return false;
						}
					}

					return true;
				},

				_generateRegEx: function(value, startsWith, caseSensitive) {
					var instance = this;

					if (!(value instanceof RegExp)) {
						value = String(value);

						var regExBuffer = [];

						if (startsWith !== false) {
							regExBuffer.push('^');
						}

						regExBuffer.push(value);

						var options;

						if (!caseSensitive) {
							options = 'i';
						}

						value = new RegExp(regExBuffer.join(''), options);
					}

					return value;
				},

				_keyFilter: function(key, value, item, index, collection) {
					var instance = this;

					return item && value.test(item[key]);
				},

				_keySorter: function(a, b) {
					var instance = this;

					var keyA = String(a).toLowerCase();
					var keyB = String(b).toLowerCase();

					var returnValue = 0;

					if (keyA > keyB) {
						returnValue = 1;
					}
					else if (keyA < keyB) {
						returnValue = -1;
					}

					return returnValue;
				},

				_sortBy: function(property, direction, fn) {
					var instance = this;

					var asc = 1;
					var tempValues = [];
					var keys = instance.get('keys');
					var values = instance.values;

					var length = values.length;

					fn = fn || A.Array.numericSort;

					if (String(direction).toLowerCase() == 'desc') {
						asc = -1;
					}

					for (var i = 0; i < length; i++) {
						tempValues.push(
							{
								key: keys[i],
								value: values[i],
								index: i
							}
						);
					}

					tempValues.sort(
						function(a, b) {
							var value = fn(a[property], b[property]) * asc;

							if (value === 0) {
								value = 1;

								if (a.index < b.index) {
									value = -1;
								}
							}

							return value;
						}
					);

					length = tempValues.length;

					var collection = {};

					for (var i = 0; i < length; i++) {
						var item = tempValues[i];
						var key = item.key;
						var value = item.value;

						values[i] = value;
						collection[key] = value;
					}

					instance.collection = collection;

					instance.fire('sort');
				}
			}
		);

		A.DataSet = DataSet;
	},
	'@VERSION',
	{
		requires: ['oop', 'collection', 'base'],
		use: []
	}
);<commit_msg>Bugfix for DataSet, prevent infinite loop if adding during .each<commit_after>AUI().add(
	'data-set',
	function(A) {
		var Lang = A.Lang;

		var DataSet = function() {
			DataSet.superclass.constructor.apply(this, arguments);
		};

		DataSet.NAME = 'compoundset';

		DataSet.ATTRS = {
			keys: {
				getter: function(value) {
					var instance = this;

					return A.Object.keys(instance.collection);
				}
			},

			first: {
				getter: function() {
					var instance = this;

					var values = instance.values;

					return values[0];
				}
			},

			includeFunctions: {
				value: false
			},

			items: {
				value: null,
				getter: function() {
					var instance = this;

					return instance.collection || {};
				}
			},

			last: {
				getter: function() {
					var instance = this;

					var values = instance.values;

					return values[values.length - 1];
				}
			},

			getKey: {
				lazyAdd: false,
				value: null,
				getter: function(value) {
					var instance = this;

					return value || instance.getKey;
				},
				setter: function(value) {
					var instance = this;

					if (Lang.isFunction(value)) {
						instance.getKey = value;
					}

					return instance.getKey;
				}
			},

			values: {
				getter: function(value) {
					var instance = this;

					return instance.values;
				},
				readOnly: true
			}
		};

		A.extend(
			DataSet,
			A.Base,
			{
				initializer: function() {
					var instance = this;

					instance.collection = {};
					instance.values = [];

					instance.length = 0;
				},

				add: function(key, obj) {
					var instance = this;

					if (arguments.length == 1) {
						obj = key;
						key = instance.getKey(obj);
					}

					var includeFunctions = instance.get('includeFunctions');

					if (!Lang.isNull(key) && !Lang.isUndefined(key)) {
						var prevVal = instance.collection[key];

						if (!Lang.isUndefined(prevVal)) {
							return instance.replace(key, obj);
						}

						if (includeFunctions || !Lang.isFunction(obj)) {
							instance.collection[key] = obj;
						}
					}

					instance.values.push(obj);

					instance.fire(
						'add',
						{
							index: instance.length,
							attrName: key,
							newVal: obj
						}
					);

					instance.length++;
				},

				addAll: function(obj) {
					var instance = this;

					var args = arguments;
					var length = args.length;

					if (length == 1) {
						args = obj;
					}

					if (length > 1 || Lang.isArray(obj)) {
						length = args.length;

						for (var i = 0; i < length; i++) {
							instance.add(args[i]);
						}
					}
					else {
						for (var i in obj) {
							var item = obj[i];

							instance.add(i, item);
						}
					}
				},

				clear: function() {
					var instance = this;

					instance.collection = {};
					instance.values = [];
					instance.length = 0;

					instance.fire('clear');
				},

				clone: function() {
					var instance = this;

					var clone = new DataSet();

					clone._collection = A.Object(instance.collection);
					clone.length = instance.length;
					clone.set('getKey', instance.get('getKey'));

					return clone;
				},

				contains: function(obj) {
					var instance = this;

					return instance.indexOf(obj) > -1;
				},

				containsKey: function(key) {
					var instance = this;

					return !(Lang.isUndefined(instance.collection[key]))
				},

				each: function(fn, context) {
					var instance = this;

					return instance._each(instance.values, fn, context);
				},

				eachKey: function(fn, context) {
					var instance = this;

					var keys = instance.get('keys');

					return instance._each(keys, fn, context);
				},

				filter: function(fn, context) {
					var instance = this;

					var filtered = new DataSet();

					filtered.set('getKey', instance.get('getKey'));

					var collection = instance.collection;
					var keys = instance.get('keys');
					var values = instance.values;

					context = context || instance;

					var filteredDataSet = filtered.collection;
					var filteredValues = filtered.values;

					var length = values.length;
					var item;

					for (var i = 0; i < length; i++) {
						item = values[i];

						if (fn.call(context, item, i, collection)) {
							filtered.add(keys[i], item);
						}
					}

					filtered.length = filteredValues.length;

					return filtered;
				},

				filterBy: function(key, value, startsWith, caseSensitive) {
					var instance = this;

					if (Lang.isUndefined(value) ||
					 	Lang.isNull(value) ||
						((Lang.isArray(value) ||
							Lang.isString(value)) && !value.length)) {

						return instance.clone();
					}

					value = instance._generateRegEx(value, startsWith, caseSensitive);

					var keyFilter = A.bind(instance._keyFilter, instance, key, value);

					return instance.filter(keyFilter);
				},

				find: function(fn, context) {
					var instance = this;

					return A.Array.find(instance.values, fn, context);
				},

				findIndex: function(fn, context, start) {
					var instance = this;

					var collection = instance.collection;
					var values = instance.values;
					var length = instance.length;

					start = start || 0;

					for (var i = start; i < length; i++) {
						if (fn.call(context, values[i], i, collection)) {
							return i;
						}
					}

					return -1;
				},

				findIndexBy: function(key, value, start, startsWith, caseSensitive) {
					var instance = this;

					if (Lang.isUndefined(value) ||
					 	Lang.isNull(value) ||
						((Lang.isArray(value) ||
							Lang.isString(value)) && !value.length)) {

						return -1;
					}

					value = instance._generateRegEx(value, startsWith, caseSensitive);

					var keyFilter = A.bind(instance._keyFilter, instance, key, value);

					return instance.findIndex(keyFilter, null, start);
				},

				getKey: function(obj) {
					var instance = this;

					return (obj.get && obj.get('id')) || obj.id;
				},

				indexOf: function(obj) {
					var instance = this;

					var values = instance.values;

					return A.Array.indexOf(values, obj);
				},

				indexOfKey: function(key) {
					var instance = this;

					var keys = instance.get('keys');

					return A.Array.indexOf(keys, key);
				},

				insert: function(index, key, obj) {
					var instance = this;

					if (arguments.length == 2) {
						obj = arguments[1];
						key = instance.getKey(obj);
					}

					if (instance.containsKey(key)) {
						instance.removeKey(key);
					}

					if (index >= instance.length) {
						return instance.add(key, obj);
					}

					instance.values.splice(index, 0, obj);

					instance.length++;

					if (!Lang.isUndefined(key) && !Lang.isNull(key)) {
						instance.collection[key] = obj;
					}

					instance.fire(
						'add',
						{
							index: instance.length,
							attrName: key,
							newVal: obj
						}
					);
				},

				invoke: function(method, args) {
					var instance = this;

					var values = instance.values;
					var length = values.length;

					if (!args) {
						args = [];
					}
					else {
						args = [].concat(args);
					}

					for (var i = 0; i < length; i++) {
						var item = values[i];
						var itemMethod = item && item[method];

						if (Lang.isFunction(itemMethod)) {
							itemMethod.apply(item, args);
						}
					}

					return instance;
				},

				item: function(key) {
					var instance = this;

					var item;

					if (Lang.isNumber(key)) {
						var values = instance.values;

						item = values[key];
					}
					else {
						item = instance.collection[key];
					}

					return item;
				},

				keySort: function(direction, fn) {
					var instance = this;

					instance._sortBy('key', direction, fn || instance._keySorter);
				},

				remove: function(obj) {
					var instance = this;

					var index = instance.indexOf(obj);

					return instance.removeAt(index);
				},

				removeAt: function(index) {
					var instance = this;

					if (index < instance.length && index >= 0) {
						var collection = instance.collection;
						var values = instance.values;

						var obj = values[index];

						values.splice(index, 1);

						var keys = instance.get('keys');
						var key = keys[index];

						if (!Lang.isUndefined(key)) {
							delete collection[key];
						}

						instance.length--;
					}
				},

				removeKey: function(key) {
					var instance = this;

					var index = instance.indexOfKey(key);

					return instance.removeAt(index);
				},

				replace: function(key, obj) {
					var instance = this;

					if (arguments.length == 1) {
						obj = key;
						key = instance.getKey(obj);
					}

					var prevVal = instance.collection[key];

					if (Lang.isUndefined(key) || Lang.isNull(key) || Lang.isUndefined(prevVal)) {
						return instance.add(key, obj);
					}

					var index = instance.indexOfKey(key);

					instance.collection[key] = obj;

					instance.fire(
						'replace',
						{
							attrName: key,
							prevVal: prevVal,
							newVal: obj
						}
					);
				},

				size: function() {
					var instance = this;

					return instance.length;
				},

				slice: function(start, end) {
					var instance = this;

					var values = instance.values;

					return values.slice.apply(values, arguments);
				},

				sort: function(direction, fn) {
					var instance = this;

					instance._sortBy('value', direction, fn);
				},

				_each: function(arr, fn, context) {
					var instance = this;

					var values = arr.slice(0);
					var length = values.length;

					context = context || instance;

					for (var i = 0; i < length; i++) {
						if (fn.call(context, values[i], i, values) === false) {
							return false;
						}
					}

					return true;
				},

				_generateRegEx: function(value, startsWith, caseSensitive) {
					var instance = this;

					if (!(value instanceof RegExp)) {
						value = String(value);

						var regExBuffer = [];

						if (startsWith !== false) {
							regExBuffer.push('^');
						}

						regExBuffer.push(value);

						var options;

						if (!caseSensitive) {
							options = 'i';
						}

						value = new RegExp(regExBuffer.join(''), options);
					}

					return value;
				},

				_keyFilter: function(key, value, item, index, collection) {
					var instance = this;

					return item && value.test(item[key]);
				},

				_keySorter: function(a, b) {
					var instance = this;

					var keyA = String(a).toLowerCase();
					var keyB = String(b).toLowerCase();

					var returnValue = 0;

					if (keyA > keyB) {
						returnValue = 1;
					}
					else if (keyA < keyB) {
						returnValue = -1;
					}

					return returnValue;
				},

				_sortBy: function(property, direction, fn) {
					var instance = this;

					var asc = 1;
					var tempValues = [];
					var keys = instance.get('keys');
					var values = instance.values;

					var length = values.length;

					fn = fn || A.Array.numericSort;

					if (String(direction).toLowerCase() == 'desc') {
						asc = -1;
					}

					for (var i = 0; i < length; i++) {
						tempValues.push(
							{
								key: keys[i],
								value: values[i],
								index: i
							}
						);
					}

					tempValues.sort(
						function(a, b) {
							var value = fn(a[property], b[property]) * asc;

							if (value === 0) {
								value = 1;

								if (a.index < b.index) {
									value = -1;
								}
							}

							return value;
						}
					);

					length = tempValues.length;

					var collection = {};

					for (var i = 0; i < length; i++) {
						var item = tempValues[i];
						var key = item.key;
						var value = item.value;

						values[i] = value;
						collection[key] = value;
					}

					instance.collection = collection;

					instance.fire('sort');
				}
			}
		);

		A.DataSet = DataSet;
	},
	'@VERSION',
	{
		requires: ['oop', 'collection', 'base'],
		use: []
	}
);<|endoftext|>


<commit_before>/*
 * Address field
 * https://github.com/tableau-mkt/jquery.addressfield
 *
 * Licensed under the MIT license.
 */
(function(factory) {
  /* istanbul ignore next */
  if (typeof module === "object" && typeof module.exports === "object") {
    factory(require("jquery"));
  } else {
    factory(jQuery);
  }
}(function factory($) {
  /**
   * Modifies an address field for this wrapped set of fields, given a config
   * representing how the country writes its addresses (conforming roughly to
   * xNAL standards), and an array of fields you desire to show (again, roughly
   * xNAL compatible).
   *
   * @param options
   *   A configuration object with the following properties:
   *   - fields: (Required) An object mapping xNAL field names to jQuery
   *     selectors corresponding to the associated form elements. Any fields in
   *     your form that are not listed here will be ignored when mutating your
   *     postal address form. Note that the "country" field is required at a
   *     minimum. A common example might look like:
   *     {
   *       country: 'select#address-country',
   *       localityname: 'input.city',
   *       administrativearea: '#address-state',
   *       postalcode: '.zipcode'
   *     }
   *   - json: One of:
   *     - A string, representing the path to a JSON resource containing postal
   *       address field configurations matching the format defined by the
   *       addressfield.json project. This project comes packaged with a release
   *       of addressfield.json for ease-of-use, but you can provide your own
   *       configuration as well!
   *     - An object, representing the exact same data in the exact same format
   *       as would be returned by the JSON request for the string version of
   *       this configuration. Useful in cases where a hard-coded configuration
   *       would be more advantageous over the extra http request.
   *   - async: (Optional) Boolean flag that represents whether the request to
   *     the JSON resource specified above will be performed synchronously or
   *     asynchronously. Defaults to true (async JSON request).
   *   - defs: Deprecated; if no JSON config is provided (neither a valid
   *     path nor a full JavaScript object), you can use this key to apply a
   *     one-time postal form mutation given a field configuration and field
   *     map. Useful for quick-and-dirty upgrades from jquery.addressfield 0.x.
   *     Use of this functionality is highly discouraged.
   *
   * @returns {*}
   *   Returns itself (useful for chaining).
   */
  $.fn.addressfield = function(options) {
    var $container = this,
        configs = $.extend({
          fields: {},
          json: null,
          async: true,
          // @deprecated Support for manual, synchronous, external control.
          defs: {fields: {}}
        }, options);

    // If a path was given for a JSON resource, load the resource and execute.
    if (typeof configs.json === 'string') {
      $.ajax({
        dataType: "json",
        url: configs.json,
        async: configs.async,
        success: function (data) {
          $.fn.addressfield.binder.call($container, configs.fields, $.fn.addressfield.transform(data));
          $(configs.fields.country).change();
        }
      });
      return $container;
    }
    // In this case, a direct configuration has been provided inline.
    else if (typeof configs.json === 'object' && configs.json !== null) {
      $.fn.addressfield.binder.call($container, configs.fields, $.fn.addressfield.transform(configs.json));
      $(configs.fields.country).change();
      return $container;
    }
    // Legacy support for manual, synchronous, external control.
    // @deprecated Remove this functionality in the next major version (2.0.x).
    else {
      return $.fn.addressfield.apply.call($container, configs.defs, configs.fields);
    }
  };

  /**
   * Applies a given field configuration against a given postal address form.
   *
   * @param config
   *   The field configuration to be applied to the postal address form.
   *
   * @param fieldMap
   *   A mapping of xNAL field names to their selectors within this form.
   *
   * @returns {*}
   *   Returns itself (useful for chaining).
   */
  $.fn.addressfield.apply = function (config, fieldMap) {
    var $container = $(this),
        fieldOrder = [],
        $element,
        selector,
        placeholder,
        fieldPos,
        field;

    // Iterate through defined address fields for this country.
    for (fieldPos in config.fields) {
      // Determine the xNAL name of this field.
      field = $.fn.addressfield.onlyKey(config.fields[fieldPos]);

      // Pick out the existing elements for the given field.
      selector = fieldMap.hasOwnProperty(field) ? fieldMap[field] : '.' + field;
      $element = $container.find(selector);

      // Account for nested fields.
      if (config.fields[fieldPos][field] instanceof Array) {
        return $.fn.addressfield.apply.call($element, {fields: config.fields[fieldPos][field]}, fieldMap);
      }
      // Otherwise perform the usual actions.
      else {
        // When swapping out labels / values for existing fields.
        // Ensure the element exists and is configured to be displayed.
        if ($element.length && fieldMap.hasOwnProperty(field)) {
          // Push this field selector onto the fieldOrder array.
          fieldOrder.push(selector);

          // Update the options.
          if (typeof config.fields[fieldPos][field].options !== 'undefined') {
            // If this field has options but it's currently a text field,
            // convert it back to a select field.
            if (!$element.is('select')) {
              $element = $.fn.addressfield.convertToSelect.call($element);
            }
            $.fn.addressfield.updateOptions.call($element, config.fields[fieldPos][field].options);
          }
          else {
            // If this field does not have options but it's currently a select
            // field, convert it back to a text field.
            if ($element.is('select')) {
              $element = $.fn.addressfield.convertToText.call($element);
            }

            // Apply a placeholder; empty one if none exists.
            placeholder = config.fields[fieldPos][field].hasOwnProperty('eg') ? config.fields[fieldPos][field].eg : '';
            $.fn.addressfield.updateEg.call($element, placeholder);
          }

          // Update the label.
          $.fn.addressfield.updateLabel.call($element, config.fields[fieldPos][field].label);
        }

        // When adding fields that didn't previously exist.
        if (!$.fn.addressfield.isVisible.call($element) && fieldMap.hasOwnProperty(field)) {
          $.fn.addressfield.showField.call($element);
        }

        // Add, update, or remove validation handling for this field.
        $.fn.addressfield.validate.call($element, field, config.fields[fieldPos][field]);
      }
    }

    // Now check for fields that are still on the page but shouldn't be.
    $.each(fieldMap, function (field_name, field_selector) {
      var $element = $container.find(field_selector);
      if ($element.length && !$.fn.addressfield.hasField(config, field_name)) {
        $.fn.addressfield.hideField.call($element);
      }
    });

    // Now ensure the fields are in their given order.
    $.fn.addressfield.orderFields.call($container, fieldOrder);

    // Trigger an addressfield:after event on the container.
    $container.trigger('addressfield:after', {config: config, fieldMap: fieldMap});

    return this;
  };

  /**
   * Binds a handler to the country form field element, which applies postal
   * address form mutations to this form container based on the selected country
   * and given xNAL field map.
   *
   * @param fieldMap
   *   A map of xNAL fields to jQuery selectors representing their corresponding
   *   form field elements.
   *
   * @param countryConfigMap
   *   A map of field configurations to country ISO codes which should match
   *   the values associated with the country select element, defined in the
   *   fieldMap above).
   */
  $.fn.addressfield.binder = function(fieldMap, countryConfigMap) {
    var $container = this;

    $container.find(fieldMap.country).bind('change', function() {
      // Trigger the apply method with the country's data.
      $.fn.addressfield.apply.call($container, countryConfigMap[this.value], fieldMap);
    });

    return $container;
  };

  /**
   * Transforms JSON data returned in the instantiation method to the format
   * expected by the binder method.
   */
  $.fn.addressfield.transform = function(data) {
    var countryMap = {},
        position;

    // Store a map of countries to their associated field configs.
    for (position in data.options) {
      countryMap[data.options[position].iso] = data.options[position];
    }

    return countryMap;
  };

  /**
   * Returns the "first" (only) key of a JavaScript object.
   */
  $.fn.addressfield.onlyKey = function (obj) {
    for (var i in obj) {
      return i;
    }
  };

  /**
   * Returns whether or not a given configuration contains a given field.
   */
  $.fn.addressfield.hasField = function (config, expectedField) {
    var pos,
        field;

    for (pos in config.fields) {
      field = $.fn.addressfield.onlyKey(config.fields[pos]);
      if (config.fields[pos][field] instanceof Array) {
        return $.fn.addressfield.hasField({fields: config.fields[pos][field]}, expectedField);
      }
      else {
        if (field === expectedField) {
          return true;
        }
      }
    }

    return false;
  };

  /**
   * Updates a given field's label with a given label.
   */
  $.fn.addressfield.updateLabel = function (label) {
    var $this = $(this),
        elementName = $this.attr('id'),
        $label = $('label[for="' + elementName + '"]') || $this.prev('label');

    $label.text(label);
  };

  /**
   * Updates a given field's expected format. By default, the placeholder text.
   */
  $.fn.addressfield.updateEg = function (example) {
    var text = example ? 'e.g. ' + example : '';
    $(this).attr('placeholder', text);
  };

  /**
   * Updates a given select field's options with given options.
   */
  $.fn.addressfield.updateOptions = function (options) {
    var $self = $(this),
        oldVal = $self.data('_saved') || $self.val();

    $self.children('option').remove();
    $.each(options, function (optionPos) {
      var value = $.fn.addressfield.onlyKey(options[optionPos]);
      $self.append($('<option></option>').attr('value', value).text(options[optionPos][value]));
    });

    // Ensure the old value is still reflected after options are updated.
    $self.val(oldVal).change();

    // Clean up the data attribute; no-op if it was not previously populated.
    $self.removeData('_saved');
  };

  /**
   * Converts a given select field to a regular textarea.
   */
  $.fn.addressfield.convertToText = function () {
    var $self = $(this),
        $input = $('<input />').attr('type', 'text');

    // Copy attributes from $self to $input.
    $.fn.addressfield.copyAttrsTo.call($self, $input);

    // Ensure the old value is still reflected after conversion.
    $input.val($self.val());

    // Replace the existing element with our new one; also return it.
    $self.replaceWith($input);
    return $input;
  };

  /**
   * Converts a given input field to a select field.
   */
  $.fn.addressfield.convertToSelect = function() {
    var $self = $(this),
        $select = $('<select></select>');

    // Copy attributes from $self to $select.
    $.fn.addressfield.copyAttrsTo.call($self, $select);

    // Save the old input value to a data attribute, for use in updateOptions.
    $select.data('_saved', $self.val());

    // Replace the existing element with our new one; also return it.
    $self.replaceWith($select);
    return $select;
  };

  /**
   * Optional integration with jQuery.validate.
   */
  $.fn.addressfield.validate = function(field, config) {
    var $this = $(this),
        methodName = 'isValid_' + field,
        rule = {},
        message = "Please check your formatting.";

    // Only proceed if jQuery.validator is installed.
    if (typeof $.validator !== 'undefined') {
      // Support pre-set validation messages.
      message = $.validator.messages.hasOwnProperty(methodName) ? $.validator.messages[methodName] : message;

      // If the provided field has a specified format...
      if (config.hasOwnProperty('format')) {
        // Create the validation method.
        $.validator.addMethod(methodName, function (value) {
          // @todo Drop jQuery 1.3 support. No need for .toString() call.
          return new RegExp(config.format).test($.trim(value.toString()));
        }, message);

        // Apply the rule.
        rule[methodName] = true;
        $this.rules('add', rule);
      }
      else {
        // If there is no format, create the validation method anyway, but have
        // it do nothing.
        $.validator.addMethod(methodName, function () {return true;}, message);
      }
    }
  };

  /**
   * Hides the field, but stores it for restoration later, if necessary.
   */
  $.fn.addressfield.hideField = function() {
    $(this).val('').hide();
    $.fn.addressfield.container.call(this).hide();
  };

  /**
   * Shows / restores the field that had been previously hidden.
   */
  $.fn.addressfield.showField = function() {
    this.show();
    $.fn.addressfield.container.call(this).show();
  };

  /**
   * Returns whether or not the field is visible.
   */
  $.fn.addressfield.isVisible = function() {
    return $(this).is(':visible');
  };

  /**
   * Returns the container element for a given field.
   */
  $.fn.addressfield.container = function() {
    var $this = $(this),
        elementName = $this.attr('id'),
        $label = $('label[for="' + elementName + '"]') || $this.prev('label');

    // @todo drop support for jQuery 1.3, just use .has()
    if (typeof $.fn.has === 'function') {
      return $this.parents().has($label).first();
    }
    else {
      return $this.parents().find(':has(label):has(#' + elementName + '):last');
    }
  };

  /**
   * Copies select HTML attributes from a given element to the supplied element.
   */
  $.fn.addressfield.copyAttrsTo = function($to) {
    var attributes = ['class', 'id', 'name', 'propdescname'],
        $this = $(this);

    $.each($this[0].attributes, function () {
      if ($.inArray(this.name, attributes) !== -1) {
        // Compatibility for IE8.
        if (this.name === 'propdescname') {
          $to.attr('name', this.value);
        }
        else {
          $to.attr(this.name, this.value);
        }
      }
    });
  };

  /**
   * Re-orders fields given an array of selectors representing fields. Note that
   * this can be called recursively if one of the values passed in the
   * order array is itself an array.
   */
  $.fn.addressfield.orderFields = function(order) {
    var $self = $(this),
        // Create an empty jQuery object.
        // @todo Remove .not(document) when dropping jQuery 1.3 support.
        $orderedContainers = $().not(document);

    // Form a jQuery object with container elements in the correct order.
    $.each(order, function (index, selector) {
      var $container = $.fn.addressfield.container.call($self.find(selector));
      $orderedContainers.push($container[0]);
    });

    // Re-append to parent in the correct order.
    $orderedContainers.detach().appendTo($self);
  };
}));
<commit_msg>Update code from https://github.com/CommandLineDesign, with modifications around variable declaration and control structure<commit_after>/*
 * Address field
 * https://github.com/tableau-mkt/jquery.addressfield
 *
 * Licensed under the MIT license.
 */
(function(factory) {
  /* istanbul ignore next */
  if (typeof module === "object" && typeof module.exports === "object") {
    factory(require("jquery"));
  } else {
    factory(jQuery);
  }
}(function factory($) {
  /**
   * Modifies an address field for this wrapped set of fields, given a config
   * representing how the country writes its addresses (conforming roughly to
   * xNAL standards), and an array of fields you desire to show (again, roughly
   * xNAL compatible).
   *
   * @param options
   *   A configuration object with the following properties:
   *   - fields: (Required) An object mapping xNAL field names to jQuery
   *     selectors corresponding to the associated form elements. Any fields in
   *     your form that are not listed here will be ignored when mutating your
   *     postal address form. Note that the "country" field is required at a
   *     minimum. A common example might look like:
   *     {
   *       country: 'select#address-country',
   *       localityname: 'input.city',
   *       administrativearea: '#address-state',
   *       postalcode: '.zipcode'
   *     }
   *   - json: One of:
   *     - A string, representing the path to a JSON resource containing postal
   *       address field configurations matching the format defined by the
   *       addressfield.json project. This project comes packaged with a release
   *       of addressfield.json for ease-of-use, but you can provide your own
   *       configuration as well!
   *     - An object, representing the exact same data in the exact same format
   *       as would be returned by the JSON request for the string version of
   *       this configuration. Useful in cases where a hard-coded configuration
   *       would be more advantageous over the extra http request.
   *   - async: (Optional) Boolean flag that represents whether the request to
   *     the JSON resource specified above will be performed synchronously or
   *     asynchronously. Defaults to true (async JSON request).
   *   - defs: Deprecated; if no JSON config is provided (neither a valid
   *     path nor a full JavaScript object), you can use this key to apply a
   *     one-time postal form mutation given a field configuration and field
   *     map. Useful for quick-and-dirty upgrades from jquery.addressfield 0.x.
   *     Use of this functionality is highly discouraged.
   *
   * @returns {*}
   *   Returns itself (useful for chaining).
   */
  $.fn.addressfield = function(options) {
    var $container = this,
        configs = $.extend({
          fields: {},
          json: null,
          async: true,
          // @deprecated Support for manual, synchronous, external control.
          defs: {fields: {}}
        }, options),
        transformedData;

    // If a path was given for a JSON resource, load the resource and execute.
    if (typeof configs.json === 'string') {
      $.ajax({
        dataType: "json",
        url: configs.json,
        async: configs.async,
        success: function (data) {
          transformedData = $.fn.addressfield.transform(data);

          $.fn.addressfield.initCountries.call($container, configs.fields.country, transformedData);
          $.fn.addressfield.binder.call($container, configs.fields, transformedData);
          $(configs.fields.country).change();
        }
      });
      return $container;
    }
    // In this case, a direct configuration has been provided inline.
    else if (typeof configs.json === 'object' && configs.json !== null) {
      transformedData = $.fn.addressfield.transform(configs.json);

      $.fn.addressfield.initCountries.call($container, configs.fields.country, transformedData);
      $.fn.addressfield.binder.call($container, configs.fields, transformedData);
      $(configs.fields.country).change();
      return $container;
    }
    // Legacy support for manual, synchronous, external control.
    // @deprecated Remove this functionality in the next major version (2.0.x).
    else {
      return $.fn.addressfield.apply.call($container, configs.defs, configs.fields);
    }
  };

  /**
   * Applies a given field configuration against a given postal address form.
   *
   * @param config
   *   The field configuration to be applied to the postal address form.
   *
   * @param fieldMap
   *   A mapping of xNAL field names to their selectors within this form.
   *
   * @returns {*}
   *   Returns itself (useful for chaining).
   */
  $.fn.addressfield.apply = function (config, fieldMap) {
    var $container = $(this),
        fieldOrder = [],
        $element,
        selector,
        placeholder,
        fieldPos,
        field;

    // Iterate through defined address fields for this country.
    for (fieldPos in config.fields) {
      // Determine the xNAL name of this field.
      field = $.fn.addressfield.onlyKey(config.fields[fieldPos]);

      // Pick out the existing elements for the given field.
      selector = fieldMap.hasOwnProperty(field) ? fieldMap[field] : '.' + field;
      $element = $container.find(selector);

      // Account for nested fields.
      if (config.fields[fieldPos][field] instanceof Array) {
        return $.fn.addressfield.apply.call($element, {fields: config.fields[fieldPos][field]}, fieldMap);
      }
      // Otherwise perform the usual actions.
      else {
        // When swapping out labels / values for existing fields.
        // Ensure the element exists and is configured to be displayed.
        if ($element.length && fieldMap.hasOwnProperty(field)) {
          // Push this field selector onto the fieldOrder array.
          fieldOrder.push(selector);

          // Update the options.
          if (typeof config.fields[fieldPos][field].options !== 'undefined') {
            // If this field has options but it's currently a text field,
            // convert it back to a select field.
            if (!$element.is('select')) {
              $element = $.fn.addressfield.convertToSelect.call($element);
            }
            $.fn.addressfield.updateOptions.call($element, config.fields[fieldPos][field].options);
          }
          else {
            // If this field does not have options but it's currently a select
            // field, convert it back to a text field.
            if ($element.is('select')) {
              $element = $.fn.addressfield.convertToText.call($element);
            }

            // Apply a placeholder; empty one if none exists.
            placeholder = config.fields[fieldPos][field].hasOwnProperty('eg') ? config.fields[fieldPos][field].eg : '';
            $.fn.addressfield.updateEg.call($element, placeholder);
          }

          // Update the label.
          $.fn.addressfield.updateLabel.call($element, config.fields[fieldPos][field].label);
        }

        // When adding fields that didn't previously exist.
        if (!$.fn.addressfield.isVisible.call($element) && fieldMap.hasOwnProperty(field)) {
          $.fn.addressfield.showField.call($element);
        }

        // Add, update, or remove validation handling for this field.
        $.fn.addressfield.validate.call($element, field, config.fields[fieldPos][field]);
      }
    }

    // Now check for fields that are still on the page but shouldn't be.
    $.each(fieldMap, function (field_name, field_selector) {
      var $element = $container.find(field_selector);
      if ($element.length && !$.fn.addressfield.hasField(config, field_name)) {
        $.fn.addressfield.hideField.call($element);
      }
    });

    // Now ensure the fields are in their given order.
    $.fn.addressfield.orderFields.call($container, fieldOrder);

    // Trigger an addressfield:after event on the container.
    $container.trigger('addressfield:after', {config: config, fieldMap: fieldMap});

    return this;
  };

  /**
  * Populates country dropdown with list of countries from provided json file if it is empty.
  *
  * @param selector
  *   Field identifying the country dropdown from user-configs.
  *
  * @param countryMap
  *   A map of country codes to country names.
  */
  $.fn.addressfield.initCountries = function(selector, countryMap) {
    var $container = this,
        $countrySelect = $container.find(selector + ':not(:has(>option))');

    if (!$countrySelect.length) {
      return;
    }

    $.each(countryMap, function(key, value) {
      $countrySelect.append($('<option></option>')
        .attr('value', key)
        .text(value.label)
      );
    });
  };

  /**
   * Binds a handler to the country form field element, which applies postal
   * address form mutations to this form container based on the selected country
   * and given xNAL field map.
   *
   * @param fieldMap
   *   A map of xNAL fields to jQuery selectors representing their corresponding
   *   form field elements.
   *
   * @param countryConfigMap
   *   A map of field configurations to country ISO codes which should match
   *   the values associated with the country select element, defined in the
   *   fieldMap above).
   */
  $.fn.addressfield.binder = function(fieldMap, countryConfigMap) {
    var $container = this;

    $container.find(fieldMap.country).bind('change', function() {
      // Trigger the apply method with the country's data.
      $.fn.addressfield.apply.call($container, countryConfigMap[this.value], fieldMap);
    });

    return $container;
  };

  /**
   * Transforms JSON data returned in the instantiation method to the format
   * expected by the binder method.
   */
  $.fn.addressfield.transform = function(data) {
    var countryMap = {},
        position;

    // Store a map of countries to their associated field configs.
    for (position in data.options) {
      countryMap[data.options[position].iso] = data.options[position];
    }

    return countryMap;
  };

  /**
   * Returns the "first" (only) key of a JavaScript object.
   */
  $.fn.addressfield.onlyKey = function (obj) {
    for (var i in obj) {
      return i;
    }
  };

  /**
   * Returns whether or not a given configuration contains a given field.
   */
  $.fn.addressfield.hasField = function (config, expectedField) {
    var pos,
        field;

    for (pos in config.fields) {
      field = $.fn.addressfield.onlyKey(config.fields[pos]);
      if (config.fields[pos][field] instanceof Array) {
        return $.fn.addressfield.hasField({fields: config.fields[pos][field]}, expectedField);
      }
      else {
        if (field === expectedField) {
          return true;
        }
      }
    }

    return false;
  };

  /**
   * Updates a given field's label with a given label.
   */
  $.fn.addressfield.updateLabel = function (label) {
    var $this = $(this),
        elementName = $this.attr('id'),
        $label = $('label[for="' + elementName + '"]') || $this.prev('label');

    $label.text(label);
  };

  /**
   * Updates a given field's expected format. By default, the placeholder text.
   */
  $.fn.addressfield.updateEg = function (example) {
    var text = example ? 'e.g. ' + example : '';
    $(this).attr('placeholder', text);
  };

  /**
   * Updates a given select field's options with given options.
   */
  $.fn.addressfield.updateOptions = function (options) {
    var $self = $(this),
        oldVal = $self.data('_saved') || $self.val();

    $self.children('option').remove();
    $.each(options, function (optionPos) {
      var value = $.fn.addressfield.onlyKey(options[optionPos]);
      $self.append($('<option></option>').attr('value', value).text(options[optionPos][value]));
    });

    // Ensure the old value is still reflected after options are updated.
    $self.val(oldVal).change();

    // Clean up the data attribute; no-op if it was not previously populated.
    $self.removeData('_saved');
  };

  /**
   * Converts a given select field to a regular textarea.
   */
  $.fn.addressfield.convertToText = function () {
    var $self = $(this),
        $input = $('<input />').attr('type', 'text');

    // Copy attributes from $self to $input.
    $.fn.addressfield.copyAttrsTo.call($self, $input);

    // Ensure the old value is still reflected after conversion.
    $input.val($self.val());

    // Replace the existing element with our new one; also return it.
    $self.replaceWith($input);
    return $input;
  };

  /**
   * Converts a given input field to a select field.
   */
  $.fn.addressfield.convertToSelect = function() {
    var $self = $(this),
        $select = $('<select></select>');

    // Copy attributes from $self to $select.
    $.fn.addressfield.copyAttrsTo.call($self, $select);

    // Save the old input value to a data attribute, for use in updateOptions.
    $select.data('_saved', $self.val());

    // Replace the existing element with our new one; also return it.
    $self.replaceWith($select);
    return $select;
  };

  /**
   * Optional integration with jQuery.validate.
   */
  $.fn.addressfield.validate = function(field, config) {
    var $this = $(this),
        methodName = 'isValid_' + field,
        rule = {},
        message = "Please check your formatting.";

    // Only proceed if jQuery.validator is installed.
    if (typeof $.validator !== 'undefined') {
      // Support pre-set validation messages.
      message = $.validator.messages.hasOwnProperty(methodName) ? $.validator.messages[methodName] : message;

      // If the provided field has a specified format...
      if (config.hasOwnProperty('format')) {
        // Create the validation method.
        $.validator.addMethod(methodName, function (value) {
          // @todo Drop jQuery 1.3 support. No need for .toString() call.
          return new RegExp(config.format).test($.trim(value.toString()));
        }, message);

        // Apply the rule.
        rule[methodName] = true;
        $this.rules('add', rule);
      }
      else {
        // If there is no format, create the validation method anyway, but have
        // it do nothing.
        $.validator.addMethod(methodName, function () {return true;}, message);
      }
    }
  };

  /**
   * Hides the field, but stores it for restoration later, if necessary.
   */
  $.fn.addressfield.hideField = function() {
    $(this).val('').hide();
    $.fn.addressfield.container.call(this).hide();
  };

  /**
   * Shows / restores the field that had been previously hidden.
   */
  $.fn.addressfield.showField = function() {
    this.show();
    $.fn.addressfield.container.call(this).show();
  };

  /**
   * Returns whether or not the field is visible.
   */
  $.fn.addressfield.isVisible = function() {
    return $(this).is(':visible');
  };

  /**
   * Returns the container element for a given field.
   */
  $.fn.addressfield.container = function() {
    var $this = $(this),
        elementName = $this.attr('id'),
        $label = $('label[for="' + elementName + '"]') || $this.prev('label');

    // @todo drop support for jQuery 1.3, just use .has()
    if (typeof $.fn.has === 'function') {
      return $this.parents().has($label).first();
    }
    else {
      return $this.parents().find(':has(label):has(#' + elementName + '):last');
    }
  };

  /**
   * Copies select HTML attributes from a given element to the supplied element.
   */
  $.fn.addressfield.copyAttrsTo = function($to) {
    var attributes = ['class', 'id', 'name', 'propdescname'],
        $this = $(this);

    $.each($this[0].attributes, function () {
      if ($.inArray(this.name, attributes) !== -1) {
        // Compatibility for IE8.
        if (this.name === 'propdescname') {
          $to.attr('name', this.value);
        }
        else {
          $to.attr(this.name, this.value);
        }
      }
    });
  };

  /**
   * Re-orders fields given an array of selectors representing fields. Note that
   * this can be called recursively if one of the values passed in the
   * order array is itself an array.
   */
  $.fn.addressfield.orderFields = function(order) {
    var $self = $(this),
        // Create an empty jQuery object.
        // @todo Remove .not(document) when dropping jQuery 1.3 support.
        $orderedContainers = $().not(document);

    // Form a jQuery object with container elements in the correct order.
    $.each(order, function (index, selector) {
      var $container = $.fn.addressfield.container.call($self.find(selector));
      $orderedContainers.push($container[0]);
    });

    // Re-append to parent in the correct order.
    $orderedContainers.detach().appendTo($self);
  };
}));
<|endoftext|>


<commit_before>/*
	jquery forces forms plugin

	Forms validation helper

	requires jquery (tested with 1.4.4)
	requires jquery.scrollTo plugin
	requires generateId plugin
	requires HTML5 constraint validation API (native browser or polyfill)
	tested with polyfill forces.html5.constraintValidationAPI

*/

(function( $ ) {
	'use strict';

	var SUBMIT_TOLERANCE = 10000, // milliseconds

	DEFAULT_STATUS_HTML = '

Please check your answers

',

	// fields that validate
	candidateForValidation = 'input, select, textarea',

	// invalidFilter
	invalidFilter = function() {
		return ! ( this.disabled || this.validity.valid );
	},

	// follow plugin conventions for storing plugin data
	// http://docs.jquery.com/Plugins/Authoring#Data
	pluginDataKey = 'forcesForms',
	pluginData = function( key, value ) {
		var dataHash = this.data( pluginDataKey ) || this.data( pluginDataKey, {}).data( pluginDataKey );

			if ( key ) {
				if ( value ) {
					dataHash[ key ] = value;
					return value;

				} else if ( typeof dataHash[ key ] !== 'undefined' ) {
					return dataHash[ key ];
				}
				return null;
			}

			return dataHash;
	},

	// helper for .label, .hint and .alert
	getLabelComponent = function( component, options ) {
		return this.map(function( index, domElement ) {

			var $element = $( domElement ),
				labelElement = null,
				foundElement = null;

			if ( typeof options === 'object' && options.level === 'group' ) {
				foundElement = $element.closest( '.group' ).find( component )[ 0 ];

			} else if ( $element.is( ':radio, :checkbox' )) {
				foundElement = $element.closest( 'fieldset' ).find( component )[ 0 ];

			} else {
				labelElement = $element.closest( 'form' ).find( 'label[for=' + domElement.id + ']' );
				foundElement = labelElement.children( component )[ 0 ];
				if ( ! foundElement ) {
					if ( component === '.hint' ) {
						labelElement.append( '' );
						foundElement = labelElement.children( component )[ 0 ];
					}
				}
			}

			return foundElement;

		});
	},

	changeValidityCheck = function() {

		var $this = $( this ),
			alertElement = $this.forcesForms( 'alert' ),
			alertLevel
		;

		// is this control valid?
		if ( this.validity.valid ) {

			alertElement.remove();

			// remove invalid class from ancestors that do not contain invalid fields
			$this.parentsUntil( 'form', '.invalid' ).filter(function() {
				return $( this ).find( candidateForValidation ).filter( invalidFilter ).length === 0;
			})
				// remove .invalid class
				.removeClass( 'invalid' )
				// remove old alerts (change handler should have already done this)
				.find( '.alert' ).remove()
			;

		} else {

			// does alert exist?
			if ( alertElement.length === 0 ) {
				alertElement = $( '' );
			}

			// show message
			alertElement.text( $this.forcesForms( 'getValidationMessage' ) );
			// append to form
			if ( $this.forcesForms( 'group' ).hasClass( 'atomic' )) {
				alertLevel = { 'level' : 'group' };
			}

			$this.forcesForms( 'label', alertLevel ).parent().find( '.label, .required' ).eq( -1 ).after( alertElement );

			// NOTE we don't flag the question as .invalid now
			// .invalid only happens on submit, to soften inline validation errors
		}
	},

	// checks for invalid elements
	// returns number of invalid elements
	submitValidityCheck = function() {

		// form object
		var form = $( this ).closest( 'form' ),

			// invalid fields
			invalid = form.find( candidateForValidation ).filter(function invalidFields() {

				// skip disabled
				if ( this.disabled ) {
					return false;
				}

				if ( ! invalidFields.cache ) {
					invalidFields.cache = {};

				} else if ( invalidFields.cache[ this.name ] === true ) {
					return false;
				}
				invalidFields.cache[ this.name ] = true;

				return this.validity && ! this.validity.valid;
			}),

			// alert container
			alert = pluginData.call( form, 'summaryElement' ) || pluginData.call( form, 'summaryElement', $( DEFAULT_STATUS_HTML )),

			// messages within alert
			messages = alert.find( 'ol' ),

			// track groups
			lastGroupSeen = true
		;

		if ( invalid.length > 0 ) {

			// remove old messages
			messages.find( 'li' ).remove();

			// add new messages
			invalid.each(function() {

				// get field
				var $this = $( this ),
					// get group (if exists)
					group = $this.parentsUntil( 'form', '.group' ),
					// get label or group label
					label = $this.forcesForms( 'label', {
						level : group.length > 0 ? 'group' : null
					}),
					// get the label id
					labelId = label[ 0 ].id || label.generateId( 'label-' + this.id )[ 0 ].id,
					// get alert item
					item = pluginData.call( $this, 'summaryElement' ) || pluginData.call( $this, 'summaryElement', $( '

' ))
				;

				if ( group.length === 0 || group[ 0 ] !== lastGroupSeen ) {

					// update last group seen
					lastGroupSeen = group[ 0 ];

					// create error message with link to label
					item
						.find( 'a' )
							.text( label.text().replace( /\?$/, '' ) + ': ' + $this.forcesForms( 'getValidationMessage' ) )
							.end()
						.appendTo( messages )
					;

				} else {
					// remove from DOM
					item.remove();
				}
			});
		}

		return invalid.length;
	},

	submitValidationHandler = function( event ) {
		// validate form
		var count = submitValidityCheck.call( this ),
			form = $( this );

		// remove invalid class from questions that do not contain invalid fields
		form.find( '.invalid' ).filter(function() {
			return $( this ).find( candidateForValidation ).filter( invalidFilter ).length === 0;
		})
			// remove .invalid class
			.removeClass( 'invalid' )
			// remove old alerts (change handler should have already done this)
			.find( '.alert' ).remove()
		;

		// anything invalid?
		if ( count > 0 ) {
			// cancel submit
			event.stopImmediatePropagation();
			event.preventDefault();

			// show the error summary
			(function( form ) {
				var summary = pluginData.call( form, 'summaryElement' );
				// hide any previous status blocks
				form.prev( '.status' ).not( summary ).remove();
				// show the new summary
				form.before( summary.fadeIn() );
				// focus/scrollTo summary element
				// required jquery.scrollTo plugin
				// http://flesler.blogspot.com/2007/10/jqueryscrollto.html
				$( window ).scrollTo( summary );
			}( form ));

			// find all the invalid fields
			form.find( candidateForValidation ).filter( invalidFilter ).each(function() {
				// update inline alerts
				changeValidityCheck.call( this );
			})
				// set .invalid on ancestor LI elements
				.parentsUntil( 'form', '.questions > li' )
				// but not sections
				.not( '.section, .compact' )
				.addClass( 'invalid' )
			;

			// cancel submit
			return false;
		}
	},

	// bind this AFTER the validation handler
	// only invoked if validation did not prevent submit
	submitDoneHandler = function( event ) {
		// remove summary element from DOM on successful submit
		var form = $( this ),
			summaryElement = pluginData.call( form, 'summaryElement' ),
			lastSubmitTimeStamp;

		if ( summaryElement ) {
			summaryElement.remove();
		}

		// is this submit event too soon after the last one?
		lastSubmitTimeStamp = pluginData.call( form, 'lastSubmitTimeStamp' );
		if ( lastSubmitTimeStamp && event.timeStamp - lastSubmitTimeStamp < SUBMIT_TOLERANCE ) {
			// cancel the submit event
			event.stopImmediatePropagation();
			event.preventDefault();
			return false;

		} else {
			// store the timestamp
			pluginData.call( form, 'lastSubmitTimeStamp', event.timeStamp );
		}
	},

	// plugin methods
	methods = {

		// $( x ).forcesForms( 'alert' ) -- get
		// get or set alert text (html not supported)
		alert : function( alertMessage ) {
			return this.map(function( index, domElement ) {

				var $element = $( domElement ),
					group;

				if ( $element.is( ':radio, :checkbox' ) === true ) {
					return $element.closest( 'fieldset' ).find( 'legend > .alert' )[ 0 ];

				} else {
					// atomic groups
					group = $element.parentsUntil( 'form', '.group' );
					if ( group.length > 0 && group.hasClass( 'atomic' )) {
						return group.find( 'legend > .alert' )[ 0 ];

					} else {
						return $( 'label[for="' + domElement.id + '"] > .alert' )[ 0 ];
					}
				}
			});
		},

		// $( x ).forcesForms( 'label' )
		// $( x ).forcesForms( 'label', { level : group })
		// return .label associated with element or containing group
		label : function( options ) {
			return getLabelComponent.call( this, '.label', options );
		},

		// $( x ).forcesForms( 'hint' )
		// $( x ).forcesForms( 'hint', { level : group })
		// return .hint associated with element or containing group
		hint : function( options ) {
			return getLabelComponent.call( this, '.hint', options );
		},

		// $( x ).forcesForms( 'question' )
		// return question element for item
		question : function( options ) {
			// looking for group?
			if ( typeof options === 'object' && options.level === 'group' ) {
				// return the group
				return this.forcesForms( 'group' );
			}

			// not looking for group
			return this.map(function( index, domElement ) {
				return $( domElement ).parentsUntil( 'form', '.questions > li' )[ 0 ];
			});
		},

		// $( x ).forcesForms( 'group' )
		// return group element for item
		group : function() {
			return this.map(function( index, domElement ) {
				return $( domElement ).parentsUntil( 'form', '.group' )[ 0 ];
			});
		},

		// $( x ).forcesForms( 'validate' )
		// binds validation handler functions
		// sets @novalidate on form to disable built-in validation
		// TODO allow this to be called multiple times without binding additional handlers!
		validate : function() {
			return this.each(function() {
				$( this ).closest( 'form' )
					// turn off native validation
					.attr( 'novalidate', true )
					// unbind and rebind handlers
					.unbind( 'submit', submitDoneHandler )
					.unbind( 'submit', submitValidationHandler )
					// validate this form
					.bind( 'submit', submitValidationHandler )
					// if validation did not cancel submit…
					.bind( 'submit', submitDoneHandler )
					// bind inline validation handlers to form elements
					.find( candidateForValidation )
						.unbind( 'change', changeValidityCheck )
						.bind( 'change', changeValidityCheck )
				;
			});
		},

		// $( x ).forcesForms( 'getValidationMessage' )
		// return String validation message, e.g. "Must be completed"
		getValidationMessage : function() {

			var validityState = this[ 0 ].validity;

			if ( typeof validityState === 'undefined' || validityState.valid === true ) {
				return '';

			} else if ( validityState.valueMissing ) {
				return 'Must be completed';

			} else if ( validityState.customError ) {
				return this[ 0 ].validationMessage;

			} else if ( validityState.typeMismatch ) {
				return 'Must be an email address';

			} else if ( validityState.patternMismatch ) {
				return 'Must use the format shown';

			} else {
				return 'Must be a valid answer';
			}
		}

	};

	$.fn.forcesForms = function( method ) {

		// Method calling logic
		// http://docs.jquery.com/Plugins/Authoring#Plugin_Methods
		if ( methods[method] ) {
			return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.forcesForms' );
		}

	};

}( jQuery ));
<commit_msg>replace event.timeStamp with new Date().getTime()<commit_after>/*
	jquery forces forms plugin

	Forms validation helper

	requires jquery (tested with 1.4.4)
	requires jquery.scrollTo plugin
	requires generateId plugin
	requires HTML5 constraint validation API (native browser or polyfill)
	tested with polyfill forces.html5.constraintValidationAPI

*/

(function( $ ) {
	'use strict';

	var SUBMIT_TOLERANCE = 10000, // milliseconds

	DEFAULT_STATUS_HTML = '

Please check your answers

',

	// fields that validate
	candidateForValidation = 'input, select, textarea',

	// invalidFilter
	invalidFilter = function() {
		return ! ( this.disabled || this.validity.valid );
	},

	// follow plugin conventions for storing plugin data
	// http://docs.jquery.com/Plugins/Authoring#Data
	pluginDataKey = 'forcesForms',
	pluginData = function( key, value ) {
		var dataHash = this.data( pluginDataKey ) || this.data( pluginDataKey, {}).data( pluginDataKey );

			if ( key ) {
				if ( value ) {
					dataHash[ key ] = value;
					return value;

				} else if ( typeof dataHash[ key ] !== 'undefined' ) {
					return dataHash[ key ];
				}
				return null;
			}

			return dataHash;
	},

	// helper for .label, .hint and .alert
	getLabelComponent = function( component, options ) {
		return this.map(function( index, domElement ) {

			var $element = $( domElement ),
				labelElement = null,
				foundElement = null;

			if ( typeof options === 'object' && options.level === 'group' ) {
				foundElement = $element.closest( '.group' ).find( component )[ 0 ];

			} else if ( $element.is( ':radio, :checkbox' )) {
				foundElement = $element.closest( 'fieldset' ).find( component )[ 0 ];

			} else {
				labelElement = $element.closest( 'form' ).find( 'label[for=' + domElement.id + ']' );
				foundElement = labelElement.children( component )[ 0 ];
				if ( ! foundElement ) {
					if ( component === '.hint' ) {
						labelElement.append( '' );
						foundElement = labelElement.children( component )[ 0 ];
					}
				}
			}

			return foundElement;

		});
	},

	changeValidityCheck = function() {

		var $this = $( this ),
			alertElement = $this.forcesForms( 'alert' ),
			alertLevel
		;

		// is this control valid?
		if ( this.validity.valid ) {

			alertElement.remove();

			// remove invalid class from ancestors that do not contain invalid fields
			$this.parentsUntil( 'form', '.invalid' ).filter(function() {
				return $( this ).find( candidateForValidation ).filter( invalidFilter ).length === 0;
			})
				// remove .invalid class
				.removeClass( 'invalid' )
				// remove old alerts (change handler should have already done this)
				.find( '.alert' ).remove()
			;

		} else {

			// does alert exist?
			if ( alertElement.length === 0 ) {
				alertElement = $( '' );
			}

			// show message
			alertElement.text( $this.forcesForms( 'getValidationMessage' ) );
			// append to form
			if ( $this.forcesForms( 'group' ).hasClass( 'atomic' )) {
				alertLevel = { 'level' : 'group' };
			}

			$this.forcesForms( 'label', alertLevel ).parent().find( '.label, .required' ).eq( -1 ).after( alertElement );

			// NOTE we don't flag the question as .invalid now
			// .invalid only happens on submit, to soften inline validation errors
		}
	},

	// checks for invalid elements
	// returns number of invalid elements
	submitValidityCheck = function() {

		// form object
		var form = $( this ).closest( 'form' ),

			// invalid fields
			invalid = form.find( candidateForValidation ).filter(function invalidFields() {

				// skip disabled
				if ( this.disabled ) {
					return false;
				}

				if ( ! invalidFields.cache ) {
					invalidFields.cache = {};

				} else if ( invalidFields.cache[ this.name ] === true ) {
					return false;
				}
				invalidFields.cache[ this.name ] = true;

				return this.validity && ! this.validity.valid;
			}),

			// alert container
			alert = pluginData.call( form, 'summaryElement' ) || pluginData.call( form, 'summaryElement', $( DEFAULT_STATUS_HTML )),

			// messages within alert
			messages = alert.find( 'ol' ),

			// track groups
			lastGroupSeen = true
		;

		if ( invalid.length > 0 ) {

			// remove old messages
			messages.find( 'li' ).remove();

			// add new messages
			invalid.each(function() {

				// get field
				var $this = $( this ),
					// get group (if exists)
					group = $this.parentsUntil( 'form', '.group' ),
					// get label or group label
					label = $this.forcesForms( 'label', {
						level : group.length > 0 ? 'group' : null
					}),
					// get the label id
					labelId = label[ 0 ].id || label.generateId( 'label-' + this.id )[ 0 ].id,
					// get alert item
					item = pluginData.call( $this, 'summaryElement' ) || pluginData.call( $this, 'summaryElement', $( '

' ))
				;

				if ( group.length === 0 || group[ 0 ] !== lastGroupSeen ) {

					// update last group seen
					lastGroupSeen = group[ 0 ];

					// create error message with link to label
					item
						.find( 'a' )
							.text( label.text().replace( /\?$/, '' ) + ': ' + $this.forcesForms( 'getValidationMessage' ) )
							.end()
						.appendTo( messages )
					;

				} else {
					// remove from DOM
					item.remove();
				}
			});
		}

		return invalid.length;
	},

	submitValidationHandler = function( event ) {
		// validate form
		var count = submitValidityCheck.call( this ),
			form = $( this );

		// remove invalid class from questions that do not contain invalid fields
		form.find( '.invalid' ).filter(function() {
			return $( this ).find( candidateForValidation ).filter( invalidFilter ).length === 0;
		})
			// remove .invalid class
			.removeClass( 'invalid' )
			// remove old alerts (change handler should have already done this)
			.find( '.alert' ).remove()
		;

		// anything invalid?
		if ( count > 0 ) {
			// cancel submit
			event.stopImmediatePropagation();
			event.preventDefault();

			// show the error summary
			(function( form ) {
				var summary = pluginData.call( form, 'summaryElement' );
				// hide any previous status blocks
				form.prev( '.status' ).not( summary ).remove();
				// show the new summary
				form.before( summary.fadeIn() );
				// focus/scrollTo summary element
				// required jquery.scrollTo plugin
				// http://flesler.blogspot.com/2007/10/jqueryscrollto.html
				$( window ).scrollTo( summary );
			}( form ));

			// find all the invalid fields
			form.find( candidateForValidation ).filter( invalidFilter ).each(function() {
				// update inline alerts
				changeValidityCheck.call( this );
			})
				// set .invalid on ancestor LI elements
				.parentsUntil( 'form', '.questions > li' )
				// but not sections
				.not( '.section, .compact' )
				.addClass( 'invalid' )
			;

			// cancel submit
			return false;
		}
	},

	// bind this AFTER the validation handler
	// only invoked if validation did not prevent submit
	submitDoneHandler = function( event ) {
		// remove summary element from DOM on successful submit
		var form = $( this ),
			summaryElement = pluginData.call( form, 'summaryElement' ),
			lastSubmitTimeStamp,
			now = ( new Date() ).getTime();

		if ( summaryElement ) {
			summaryElement.remove();
		}

		// is this submit event too soon after the last one?
		lastSubmitTimeStamp = pluginData.call( form, 'lastSubmitTimeStamp' );
		if ( lastSubmitTimeStamp && now - lastSubmitTimeStamp < SUBMIT_TOLERANCE ) {
			// cancel the submit event
			event.stopImmediatePropagation();
			event.preventDefault();
			return false;

		} else {
			// store the timestamp
			pluginData.call( form, 'lastSubmitTimeStamp', now );
		}
	},

	// plugin methods
	methods = {

		// $( x ).forcesForms( 'alert' ) -- get
		// get or set alert text (html not supported)
		alert : function( alertMessage ) {
			return this.map(function( index, domElement ) {

				var $element = $( domElement ),
					group;

				if ( $element.is( ':radio, :checkbox' ) === true ) {
					return $element.closest( 'fieldset' ).find( 'legend > .alert' )[ 0 ];

				} else {
					// atomic groups
					group = $element.parentsUntil( 'form', '.group' );
					if ( group.length > 0 && group.hasClass( 'atomic' )) {
						return group.find( 'legend > .alert' )[ 0 ];

					} else {
						return $( 'label[for="' + domElement.id + '"] > .alert' )[ 0 ];
					}
				}
			});
		},

		// $( x ).forcesForms( 'label' )
		// $( x ).forcesForms( 'label', { level : group })
		// return .label associated with element or containing group
		label : function( options ) {
			return getLabelComponent.call( this, '.label', options );
		},

		// $( x ).forcesForms( 'hint' )
		// $( x ).forcesForms( 'hint', { level : group })
		// return .hint associated with element or containing group
		hint : function( options ) {
			return getLabelComponent.call( this, '.hint', options );
		},

		// $( x ).forcesForms( 'question' )
		// return question element for item
		question : function( options ) {
			// looking for group?
			if ( typeof options === 'object' && options.level === 'group' ) {
				// return the group
				return this.forcesForms( 'group' );
			}

			// not looking for group
			return this.map(function( index, domElement ) {
				return $( domElement ).parentsUntil( 'form', '.questions > li' )[ 0 ];
			});
		},

		// $( x ).forcesForms( 'group' )
		// return group element for item
		group : function() {
			return this.map(function( index, domElement ) {
				return $( domElement ).parentsUntil( 'form', '.group' )[ 0 ];
			});
		},

		// $( x ).forcesForms( 'validate' )
		// binds validation handler functions
		// sets @novalidate on form to disable built-in validation
		// TODO allow this to be called multiple times without binding additional handlers!
		validate : function() {
			return this.each(function() {
				$( this ).closest( 'form' )
					// turn off native validation
					.attr( 'novalidate', true )
					// unbind and rebind handlers
					.unbind( 'submit', submitDoneHandler )
					.unbind( 'submit', submitValidationHandler )
					// validate this form
					.bind( 'submit', submitValidationHandler )
					// if validation did not cancel submit…
					.bind( 'submit', submitDoneHandler )
					// bind inline validation handlers to form elements
					.find( candidateForValidation )
						.unbind( 'change', changeValidityCheck )
						.bind( 'change', changeValidityCheck )
				;
			});
		},

		// $( x ).forcesForms( 'getValidationMessage' )
		// return String validation message, e.g. "Must be completed"
		getValidationMessage : function() {

			var validityState = this[ 0 ].validity;

			if ( typeof validityState === 'undefined' || validityState.valid === true ) {
				return '';

			} else if ( validityState.valueMissing ) {
				return 'Must be completed';

			} else if ( validityState.customError ) {
				return this[ 0 ].validationMessage;

			} else if ( validityState.typeMismatch ) {
				return 'Must be an email address';

			} else if ( validityState.patternMismatch ) {
				return 'Must use the format shown';

			} else {
				return 'Must be a valid answer';
			}
		}

	};

	$.fn.forcesForms = function( method ) {

		// Method calling logic
		// http://docs.jquery.com/Plugins/Authoring#Plugin_Methods
		if ( methods[method] ) {
			return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error( 'Method ' +  method + ' does not exist on jQuery.forcesForms' );
		}

	};

}( jQuery ));
<|endoftext|>


<commit_before>(function(c){var b=0;c.fn.krakatoa=function(e){var e=c.extend({},c.fn.krakatoa.defaults,e);return this.each(function(){var p,n,g=c(this),j=g.children().length,f,r,m,h,q,k,o=0,l;
l=(c(this).data("settings"))?c.extend({},e,d(c(this).data("settings"))):e;if(g.data("krakatoa")){return;}g.attr("data-krakatoa",true);g.html('

'+g.html()+"
");
f=g.find(".krakatoa-container");g.css({position:"relative",width:l.width,display:l.display});f.css({overflow:"hidden",position:"relative"});f.children().css({position:"absolute",top:0,left:0,display:"none"});
if(l.items<j){g.find(".krakatoa-control").append('

«

»

');
g.find(".arrow a").on("click touchstart",{settings:l},a);if(!l.arrows){g.find(".arrows").css("display","none");}if(l.buttons){n='
';
for(m=0;m<j/l.items;m++){n+='
'+m+"
";}n+="
";g.find(".krakatoa-control").append(n);g.find(".buttons a").on("click touchstart",{settings:l},a);
g.find(".buttons").find("li").eq(l.first).addClass("active-button");}}h=g.width();k=(h-(l.items-1)*l.gutter)/l.items;for(m=0;m<j;m++){r=f.children().eq(m);
r.css("width",k);if(l.height==="max"){q=r.outerHeight(true);if(q>o){o=q;}}}for(m=0;m<l.items&&l.first+m<j;m++){r=f.children().eq(l.first+m);r.addClass("current").css({display:"block",left:(k+l.gutter)*m});
if(l.height!=="max"){o=l.height==="auto"?r.outerHeight(true):l.height;}}g.attr("data-current",l.first);f.css("height",o);if(l.autoplay){l.playing=true;
c.fn.krakatoa.play(l,g);g.on("mouseleave",function(){c.fn.krakatoa.play(l,g);});g.on("mouseover",function(){clearTimeout(b);l.playing=false;});}else{l.playing=false;
}});};c.fn.krakatoa.play=function(e,f){b=window.setTimeout(function(){f.find(".arrow-"+e.direction).trigger("click");},e.delay);if(e.autoplay){e.playing=true;
}};c.fn.krakatoa.defaults={width:"400px",height:"300px",display:"block",arrows:true,buttons:true,items:1,first:0,gutter:10,loop:false,autoplay:false,direction:"right",delay:2000,duration:500};
function a(q){var w=c(this),h=w.closest(".krakatoa-control").parent(),f=h.find(".krakatoa-container"),r=parseInt(h.attr("data-current")),k=f.children().length,o,m,p,g,t,v,l,s=0,u=c.Deferred(),n=q.data.settings,j=0;
q.preventDefault();if(w.parent().attr("data-move")){m=w.parent().data("move");p=r+n.items*m;if(n.loop&&(p<0||p>=k)){p=Math.ceil(k/n.items)*n.items-p*m;
}else{if(p<0||p>=k){if(n.playing){n.playing=false;}return;}}}else{if(n.buttons){if(w.hasClass("active-button")){return;}m=(w.parent().index()*n.items>r)?1:-1;
p=w.parent().index()*n.items;}}w.off("click touchstart").on("click touchstart",function(i){i.preventDefault();});g=h.width();l=(g-(n.items-1)*n.gutter)/n.items;
for(o=0;o<n.items;o++){v=f.children().eq(r+o);v.removeClass("current").animate({left:-(g+n.gutter)*m+(l+n.gutter)*o},n.duration,"linear",function(){c(this).css({left:0,display:"none"});
});if(p+o>k-1){continue;}j++;v=f.children().eq(p+o);v.addClass("current").css({display:"block",left:(g+n.gutter)*m+(l+n.gutter)*o}).animate({left:(l+n.gutter)*o},n.duration,"linear",function(){j--;
if(j===0){u.resolve();}});if(n.height==="auto"){t=v.outerHeight(true);if(t>s){s=t;}f.css("height",s);}}h.attr("data-current",p);u.done(function(){if(n.playing){c.fn.krakatoa.play(n,h);
}w.off("click touchstart");w.on("click touchstart",{settings:n},a);});r=Math.round(p/n.items);if(n.buttons){h.find(".active-button").removeClass("active-button").parent().children().eq(r).addClass("active-button");
}}function d(f){var h=new Object(),j=[],e=0,g;if(typeof f!=="string"){return;}f=f.replace(/[{}\s]/g,"");j=f.split(",");for(e;e<j.length;e++){g=j[e].split(":");
if(!isNaN(g[1]-0)){if(g[1]%1===0){g[1]=parseInt(g[1]);}else{g[1]=parseFloat(g[1]);}}else{if(g[1].toLowerCase()=="true"||g[1].toLowerCase()=="false"){g[1]=(g[1]=="true");
}}h[g[0]]=g[1];}return h;}}(jQuery));<commit_msg>Add info to minified file.<commit_after>/**
 * Krakatoa
 * https://github.com/davidlpz/krakatoa
 */
(function(c){var b=0;c.fn.krakatoa=function(e){var e=c.extend({},c.fn.krakatoa.defaults,e);return this.each(function(){var p,n,g=c(this),j=g.children().length,f,r,m,h,q,k,o=0,l;
l=(c(this).data("settings"))?c.extend({},e,d(c(this).data("settings"))):e;if(g.data("krakatoa")){return;}g.attr("data-krakatoa",true);g.html('

'+g.html()+"
");
f=g.find(".krakatoa-container");g.css({position:"relative",width:l.width,display:l.display});f.css({overflow:"hidden",position:"relative"});f.children().css({position:"absolute",top:0,left:0,display:"none"});
if(l.items<j){g.find(".krakatoa-control").append('

«

»

');
g.find(".arrow a").on("click touchstart",{settings:l},a);if(!l.arrows){g.find(".arrows").css("display","none");}if(l.buttons){n='
';
for(m=0;m<j/l.items;m++){n+='
'+m+"
";}n+="
";g.find(".krakatoa-control").append(n);g.find(".buttons a").on("click touchstart",{settings:l},a);
g.find(".buttons").find("li").eq(l.first).addClass("active-button");}}h=g.width();k=(h-(l.items-1)*l.gutter)/l.items;for(m=0;m<j;m++){r=f.children().eq(m);
r.css("width",k);if(l.height==="max"){q=r.outerHeight(true);if(q>o){o=q;}}}for(m=0;m<l.items&&l.first+m<j;m++){r=f.children().eq(l.first+m);r.addClass("current").css({display:"block",left:(k+l.gutter)*m});
if(l.height!=="max"){o=l.height==="auto"?r.outerHeight(true):l.height;}}g.attr("data-current",l.first);f.css("height",o);if(l.autoplay){l.playing=true;
c.fn.krakatoa.play(l,g);g.on("mouseleave",function(){c.fn.krakatoa.play(l,g);});g.on("mouseover",function(){clearTimeout(b);l.playing=false;});}else{l.playing=false;
}});};c.fn.krakatoa.play=function(e,f){b=window.setTimeout(function(){f.find(".arrow-"+e.direction).trigger("click");},e.delay);if(e.autoplay){e.playing=true;
}};c.fn.krakatoa.defaults={width:"400px",height:"300px",display:"block",arrows:true,buttons:true,items:1,first:0,gutter:10,loop:false,autoplay:false,direction:"right",delay:2000,duration:500};
function a(q){var w=c(this),h=w.closest(".krakatoa-control").parent(),f=h.find(".krakatoa-container"),r=parseInt(h.attr("data-current")),k=f.children().length,o,m,p,g,t,v,l,s=0,u=c.Deferred(),n=q.data.settings,j=0;
q.preventDefault();if(w.parent().attr("data-move")){m=w.parent().data("move");p=r+n.items*m;if(n.loop&&(p<0||p>=k)){p=Math.ceil(k/n.items)*n.items-p*m;
}else{if(p<0||p>=k){if(n.playing){n.playing=false;}return;}}}else{if(n.buttons){if(w.hasClass("active-button")){return;}m=(w.parent().index()*n.items>r)?1:-1;
p=w.parent().index()*n.items;}}w.off("click touchstart").on("click touchstart",function(i){i.preventDefault();});g=h.width();l=(g-(n.items-1)*n.gutter)/n.items;
for(o=0;o<n.items;o++){v=f.children().eq(r+o);v.removeClass("current").animate({left:-(g+n.gutter)*m+(l+n.gutter)*o},n.duration,"linear",function(){c(this).css({left:0,display:"none"});
});if(p+o>k-1){continue;}j++;v=f.children().eq(p+o);v.addClass("current").css({display:"block",left:(g+n.gutter)*m+(l+n.gutter)*o}).animate({left:(l+n.gutter)*o},n.duration,"linear",function(){j--;
if(j===0){u.resolve();}});if(n.height==="auto"){t=v.outerHeight(true);if(t>s){s=t;}f.css("height",s);}}h.attr("data-current",p);u.done(function(){if(n.playing){c.fn.krakatoa.play(n,h);
}w.off("click touchstart");w.on("click touchstart",{settings:n},a);});r=Math.round(p/n.items);if(n.buttons){h.find(".active-button").removeClass("active-button").parent().children().eq(r).addClass("active-button");
}}function d(f){var h=new Object(),j=[],e=0,g;if(typeof f!=="string"){return;}f=f.replace(/[{}\s]/g,"");j=f.split(",");for(e;e<j.length;e++){g=j[e].split(":");
if(!isNaN(g[1]-0)){if(g[1]%1===0){g[1]=parseInt(g[1]);}else{g[1]=parseFloat(g[1]);}}else{if(g[1].toLowerCase()=="true"||g[1].toLowerCase()=="false"){g[1]=(g[1]=="true");
}}h[g[0]]=g[1];}return h;}}(jQuery));<|endoftext|>


<commit_before>(function ($) {
    function _userAlert(title, text)
    {
        $('<div/>').append(
            $('<pre/>').html(text)
        ).dialog({
            title: title,
            close: function () {
                $(this).closest('.ui-dialog').remove();
            }
        });
    }

    // jQuery AJAX error handler
    function _showErrors(jqXHR)
    {
        try {
            var data = $.parseJSON(jqXHR.responseText);
            $.each(data.form, function (field, errors) {
                this.find('*[name="'+field+'"]:first').before(_createErrorList(errors));
            }.bind(this));
            if (data.error) {
                this.find('form').addBack('form').prepend(_createErrorList([data.error]));
            }
        }
        catch (e) {
            // e.g. simple or empty strings
            console.log(e.message);
        }
    }

    function _createErrorList(errors)
    {
        var $ul = $('<ul class="error"/>');
        var $li = $('<li/>');
        $.each(errors, function (index, error) {
            $li.clone().text(error).appendTo($ul);
        });
        return $ul;
    }

    /**
     * Create a jQueryUI dialog from the element. The AJAX URL, data, and method
     * are read from the contained form.
     *
     * @param (object) options [optional] jQueryUI dialog options / plugin options
     * @param (function) success [optional] jQuery AJAX success handler
     * @return jQuery
     */
    $.fn.createDialog = function (options, success) {
        if (typeof options === 'function') {
            success = options;
        }
        if (typeof options !== 'object') { // null is ignored in $.extend()
            options = {};
        }
        var plugin  = $.fn.createDialog;
        var setting = $.extend({}, plugin.defaults, options);

        setting.buttons = [{
            text:  plugin.translate(setting.language, setting.actionLabel),
            click: function (evt) {
                var button  = evt.target; // the 'Save' button
                var $dialog = $(this);
                var $form   = $dialog.find('form').addBack('form');
                if ($form.find(':invalid').length > 0) {
                    return false;
                }

                button.disabled = true;
                $dialog.find('ul.error').remove();

                var ajax = $.ajax($form.prop('action'), {
                    type: $form.prop('method'),
                    data: $form.serialize(),
                    context: $dialog,
                    statusCode: {
                        400: _showErrors,
                        500: function (jqXHR, textStatus, errorThrown) {
                            this.dialog('close');
                            _userAlert(plugin.translate(setting.language, 'Error'), jqXHR.responseText || errorThrown);
                        }
                    }
                }).always(function () {
                    button.disabled = false;
                });

                if (setting.autoClose) {
                    ajax.done(function () {
                        this.dialog('close');
                    });
                }

                if (typeof success === 'function') {
                    ajax.done(success);
                }

                if (typeof setting.success === 'function') {
                    ajax.done(setting.success);
                }
            }
        }, {
            text:  plugin.translate(setting.language, 'Cancel'),
            click: function () {
                $(this).dialog('close');
            }
        }];

        // dialog() is a widget itself, so there’s no need to use each()
        return this.dialog(setting);
    };

    // global defaults
    $.fn.createDialog.defaults = {
        // dialog options:

        autoOpen: false,
        modal: true,
        width: 500,

        // plugin options:

        // The language to be used for translating buttons and labels.
        language: 'en',
        // The name to be used on the "submit" button.
        actionLabel: 'Save',
        // Close the dialog automatically if the AJAX submit was successful.
        autoClose: true
    };

    $.fn.createDialog.dictionary = {
        de: {
            Cancel: 'Abbrechen',
            Delete: 'Löschen',
            Edit:   'Bearbeiten',
            Error:  'Fehler',
            Save:   'Speichern'
        }
    };

    $.fn.createDialog.translate = function (language, key) {
        if (!(language in $.fn.createDialog.dictionary)) {
            return key;
        }
        var dictionary = $.fn.createDialog.dictionary[language];
        if (key in dictionary) {
            return dictionary[key];
        }
        return key;
    };
}(jQuery));
<commit_msg>deleted outdated source file<commit_after><|endoftext|>


<commit_before>angular.module('n52.core.locate', ['n52.core.station'])
        .controller('SwcLocateButtonCtrl', ['$scope', 'leafletData', function ($scope, leafletData) {
                $scope.isToggled = false;
                var marker;
                leafletData.getMap().then(function (map) {
                    map.on('locationfound', function (evt, args) {
                        removeMarker(map);
                        marker = L.marker(evt.latlng, {}).addTo(map);
                    })
                })
                $scope.locateUser = function () {
                    $scope.isToggled = !$scope.isToggled;
                    leafletData.getMap().then(function (map) {
                        if ($scope.isToggled) {
                            map.locate({
                                watch: true,
                                setView: true
                            });
                        } else {
                            map.stopLocate();
                            removeMarker(map);
                        }
                    });
                };
                removeMarker = function (map) {
                    if (angular.isDefined(marker)) {
                        map.removeLayer(marker);
                    }
                }
            }]);
        <commit_msg>extract locate functionality to service<commit_after>angular.module('n52.core.locate', ['n52.core.station'])
        .controller('SwcLocateButtonCtrl', ['$scope', 'leafletData', 'locateService', function ($scope, leafletData, locateService) {
                $scope.isToggled = false;
                $scope.locateUser = function () {
                    $scope.isToggled = !$scope.isToggled;
                    locateService.locate($scope.isToggled);
                };

            }])
        .factory('locateService', ['leafletData',
            function (leafletData) {
                var marker;
                leafletData.getMap().then(function (map) {
                    map.on('locationfound', function (evt, args) {
                        removeMarker(map);
                        marker = L.marker(evt.latlng, {}).addTo(map);
                    })
                });
                locate = function(search){
                    leafletData.getMap().then(function (map) {
                        if (search) {
                            map.locate({
                                watch: true,
                                setView: true
                            });
                        } else {
                            map.stopLocate();
                            removeMarker(map);
                        }
                    });
                }
                removeMarker = function (map) {
                    if (angular.isDefined(marker)) {
                        map.removeLayer(marker);
                    }
                }
                return {
                    locate: locate
                }
            }]);<|endoftext|>