<commit_before>AUI.add('dialog', function(A) {

var L = A.Lang,
	isBoolean = L.isBoolean,
	isNumber = L.isNumber,
	isString = L.isString,
	isArray = L.isArray,

	ADD_CLASS = 'addClass',
	ANCHOR = 'a',
	BLANK = '',
	BODY_CONTENT = 'bodyContent',
	BOUNDING_BOX = 'boundingBox',
	BUTTON = 'button',
	BUTTONS = 'buttons',
	CLOSE = 'close',
	CONSTRAIN_TO_VIEWPORT = 'constrain2view',
	CONTAINER = 'container',
	CONTENT_BOX = 'contentBox',
	DD = 'dd',
	DEFAULT = 'default',
	DIALOG = 'dialog',
	DOT = '.',
	DRAGGABLE = 'draggable',
	DRAG_INSTANCE = 'dragInstance',
	FOOTER_CONTENT = 'footerContent',
	GROUP = 'group',
	HD = 'hd',
	HEADER = 'header',
	HEADER_CONTENT = 'headerContent',
	HOVER = 'hover',
	ICON = 'icon',
	INNER_HTML = 'innerHTML',
	IO = 'io',
	LOADING = 'loading',
	POST = 'POST',
	REMOVE_CLASS = 'removeClass',
	STACK = 'stack',
	STATE = 'state',
	TITLE = 'title',
	TOOL = 'tool',
	WIDGET = 'widget',

	getCN = A.ClassNameManager.getClassName,

	CSS_DIALOG_BUTTON = getCN(DIALOG, BUTTON),
	CSS_DIALOG_BUTTON_CONTAINER = getCN(DIALOG, BUTTON, CONTAINER),
	CSS_DIALOG_BUTTON_DEFAULT = getCN(DIALOG, BUTTON, DEFAULT),
	CSS_DIALOG_CLOSE = getCN(DIALOG, CLOSE),
	CSS_DIALOG_TITLE = getCN(DIALOG, TITLE),
	CSS_ICON = getCN(ICON),
	CSS_ICON_CLOSE = getCN(ICON, CLOSE),
	CSS_ICON_LOADING = getCN(ICON, LOADING),
	CSS_PREFIX = getCN(DD),
	CSS_STATE_DEFAULT = getCN(STATE, DEFAULT),
	CSS_STATE_HOVER = getCN(STATE, HOVER),
	CSS_TOOL = getCN(TOOL),
	CSS_WIDGET_HD = getCN(WIDGET, HD),

	TPL_LOADING = '

';

function Dialog(config) {
	Dialog.superclass.constructor.apply(this, arguments);
}

A.mix(Dialog, {
	NAME: DIALOG,

	ATTRS: {
		buttons: {
			value: [],
			validator: isArray
		},

		constrain2view: {
			value: true,
			validator: isBoolean
		},

		draggable: {
			lazyAdd: true,
			value: false,
			setter: function(v) {
				console.log('_setDraggable');
				return this._setDraggable(v);
			}
		},

		dragInstance: {
			value: null
		},

		group: {
			value: DEFAULT,
			validator: isString
		},

		headerContent: {
			writeOnce: true,
			getter: function() {
				return this.titleContainter;
			}
		},

		io: {
			lazyAdd: true,
			value: null,
			setter: function(v) {
				console.log('_setIO');
				return this._setIO(v);
			}
		},

		stack: {
			lazyAdd: true,
			value: false,
			setter: function(v) {
				console.log('_setStack');
				return this._setStack(v);
			},
			validator: isBoolean
		},

		title: {
			value: BLANK,
			validator: isString
		}
	}
});

A.extend(Dialog, A.Overlay, {
	/*
	* Lifecycle
	*/
	renderUI: function () {
		var instance = this;

		instance._renderElements();
	},

	bindUI: function () {
		var instance = this;

		instance._bindElements();
	},

	renderer: function() {
		var instance = this;

		Dialog.superclass.renderer.apply(instance, arguments);

		instance._afterRenderer();
	},

	destructor: function() {
		var instance = this;

		if (instance.OverlayManager) {
			instance.OverlayManager.destroy();
		}

		instance.get(BOUNDING_BOX).remove();
	},

	/*
	* Methods
	*/
	_bindElements: function () {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);
		var closeIconContainter = instance.closeIconContainter;

		var closeFn = function(event) {
			var method = { mouseover: ADD_CLASS, mouseout: REMOVE_CLASS }[event.type];
			event.currentTarget[method](CSS_STATE_HOVER);
		};

		closeIconContainter.on('mouseover', closeFn);
		closeIconContainter.on('mouseout', closeFn);

		closeIconContainter.on('click', function(event) {
			instance.hide();
			instance.fire('close');
		});

		boundingBox.on('mousedown', function() {
			if (instance.OverlayManager) {
				instance.OverlayManager.bringToTop();
			}

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

		instance.after('titleChange', this._afterSetTitle);
	},

	_renderElements: function() {
		var instance = this;

		instance.titleContainter = A.Node.create('

');
		instance.closeIconContainter = A.Node.create('');
		instance.closeIcon = A.Node.create('');

		var closeIcon = instance.closeIcon;
		var closeIconContainter = instance.closeIconContainter;
		var title = instance.get(TITLE);
		var titleContainter = instance.titleContainter;

		closeIcon.addClass(CSS_ICON);
		closeIcon.addClass(CSS_ICON_CLOSE);
		closeIconContainter.addClass(CSS_DIALOG_CLOSE);
		closeIconContainter.addClass(CSS_STATE_DEFAULT);
		closeIconContainter.addClass(CSS_TOOL);
		titleContainter.addClass(CSS_DIALOG_TITLE);

		instance.titleContainter.set(INNER_HTML, title);
	},

	_afterRenderer: function() {
		var instance = this;
		var headerNode = instance.headerNode;
		var stack = instance.get(STACK);
		var closeIconContainter = instance.closeIconContainter;

		headerNode.addClass(CSS_STATE_DEFAULT);

		headerNode.append(instance.titleContainter);
		headerNode.append(closeIconContainter);
		closeIconContainter.append(instance.closeIcon);

		instance._initButtons();

		// forcing lazyAdd:true attrs call the setter
		instance.get(DRAGGABLE);
		instance.get(IO);
	},

	_initButtons: function() {
		var instance = this;
		var buttons = instance.get(BUTTONS);
		var container = A.Node.create('

');
		var nodeModel = A.Node.create('<button></button>');

		container.addClass(CSS_DIALOG_BUTTON_CONTAINER);
		nodeModel.addClass(CSS_DIALOG_BUTTON);

		A.each(buttons, function(button, i) {
			var node = nodeModel.cloneNode();

			if (button.isDefault) {
				node.addClass(CSS_DIALOG_BUTTON_DEFAULT);
			}

			if (button.handler) {
				node.on('click', A.bind(button.handler, instance));
			}

			node.set(INNER_HTML, button.text || BLANK);

			container.append(node);
		});

		if (buttons.length) {
			instance.set(FOOTER_CONTENT, container);
		}
	},

	_setDraggable: function(value) {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);

		var destroyDraggable = function() {
			var dragInstance = instance.get(DRAG_INSTANCE);

			if (dragInstance) {
				// TODO - YUI3 has a bug when destroy and recreates
				dragInstance.destroy();
				dragInstance.unplug(A.Plugin.DDConstrained);
			}
		};

		AUI().use('dd-constrain', function(A) {
			A.DD.DDM.CSS_PREFIX = CSS_PREFIX;

			if (value) {
				var defaults = {
					node: boundingBox,
					handles: [ DOT + CSS_WIDGET_HD ]
				};
				var dragOptions = A.merge(defaults, instance.get(DRAGGABLE) || {});

				// change the drag scope callback to execute using the dialog scope
				if (dragOptions.on) {
					A.each(dragOptions.on, function(fn, eventName) {
						dragOptions.on[eventName] = A.bind(fn, instance);
					});
				}

				destroyDraggable();

				var dragInstance = new A.DD.Drag(dragOptions);

				dragInstance.plug(A.Plugin.DDConstrained, {
					constrain2view: instance.get(CONSTRAIN_TO_VIEWPORT)
				});

				instance.set(DRAG_INSTANCE, dragInstance);
			}
			else {
				destroyDraggable();
			}
		});

		return value;
	},

	_setIO: function(value){
		var instance = this;

		if (value && !instance.get(BODY_CONTENT)) {
			instance.set(BODY_CONTENT, TPL_LOADING);
		}

		AUI().use('io-stdmod', function(A) {
			if (value) {
				instance.unplug(A.Plugin.StdModIOPlugin);

				value.uri = value.uri || value.url;

				value.cfg = A.merge({
					method: POST
				},
				value.cfg);

				var data = value.cfg.data;

				if (typeof data == 'object') {
					value.cfg.data = A.toQueryString(data);
				}

				instance.plug(A.Plugin.StdModIOPlugin, value);

				if (instance.io) {
					instance.io.refresh();
				}
			}
			else {
				instance.unplug(A.Plugin.StdModIOPlugin);
			}
		});

		return value;
	},

	_setStack: function(value) {
		var instance = this;

		AUI().use('overlay-manager', function(A) {
			if (value) {
				instance.unplug(A.Plugin.OverlayManager);

				instance.plug(A.Plugin.OverlayManager, {
					group: instance.get(GROUP)
				});
			}
			else {
				instance.unplug(A.Plugin.OverlayManager);
			}
		});

		return value;
	},

	/*
	* Attribute Listeners
	*/
	_afterSetTitle: function(event) {
		var instance = this;

		instance.titleContainter.set(INNER_HTML, event.newVal);
	}
});

A.Dialog = Dialog;

}, '@VERSION', { requires: [ 'overlay', 'plugin' ], use: [ 'dd-constrain', 'overlay-manager', 'io-stdmod' ] });<commit_msg>Source formatting<commit_after>AUI.add('dialog', function(A) {

var L = A.Lang,
	isBoolean = L.isBoolean,
	isNumber = L.isNumber,
	isString = L.isString,
	isArray = L.isArray,

	ADD_CLASS = 'addClass',
	ANCHOR = 'a',
	BLANK = '',
	BODY_CONTENT = 'bodyContent',
	BOUNDING_BOX = 'boundingBox',
	BUTTON = 'button',
	BUTTONS = 'buttons',
	CLOSE = 'close',
	CONSTRAIN_TO_VIEWPORT = 'constrain2view',
	CONTAINER = 'container',
	CONTENT_BOX = 'contentBox',
	DD = 'dd',
	DEFAULT = 'default',
	DIALOG = 'dialog',
	DOT = '.',
	DRAGGABLE = 'draggable',
	DRAG_INSTANCE = 'dragInstance',
	FOOTER_CONTENT = 'footerContent',
	GROUP = 'group',
	HD = 'hd',
	HEADER = 'header',
	HEADER_CONTENT = 'headerContent',
	HOVER = 'hover',
	ICON = 'icon',
	INNER_HTML = 'innerHTML',
	IO = 'io',
	LOADING = 'loading',
	POST = 'POST',
	REMOVE_CLASS = 'removeClass',
	STACK = 'stack',
	STATE = 'state',
	TITLE = 'title',
	TOOL = 'tool',
	WIDGET = 'widget',

	getCN = A.ClassNameManager.getClassName,

	CSS_DIALOG_BUTTON = getCN(DIALOG, BUTTON),
	CSS_DIALOG_BUTTON_CONTAINER = getCN(DIALOG, BUTTON, CONTAINER),
	CSS_DIALOG_BUTTON_DEFAULT = getCN(DIALOG, BUTTON, DEFAULT),
	CSS_DIALOG_CLOSE = getCN(DIALOG, CLOSE),
	CSS_DIALOG_TITLE = getCN(DIALOG, TITLE),
	CSS_ICON = getCN(ICON),
	CSS_ICON_CLOSE = getCN(ICON, CLOSE),
	CSS_ICON_LOADING = getCN(ICON, LOADING),
	CSS_PREFIX = getCN(DD),
	CSS_STATE_DEFAULT = getCN(STATE, DEFAULT),
	CSS_STATE_HOVER = getCN(STATE, HOVER),
	CSS_TOOL = getCN(TOOL),
	CSS_WIDGET_HD = getCN(WIDGET, HD),

	TPL_LOADING = '

';

function Dialog(config) {
	Dialog.superclass.constructor.apply(this, arguments);
}

A.mix(Dialog, {
	NAME: DIALOG,

	ATTRS: {
		buttons: {
			value: [],
			validator: isArray
		},

		constrain2view: {
			value: true,
			validator: isBoolean
		},

		draggable: {
			lazyAdd: true,
			value: false,
			setter: function(v) {
				return this._setDraggable(v);
			}
		},

		dragInstance: {
			value: null
		},

		group: {
			value: DEFAULT,
			validator: isString
		},

		headerContent: {
			writeOnce: true,
			getter: function() {
				return this.titleContainter;
			}
		},

		io: {
			lazyAdd: true,
			value: null,
			setter: function(v) {
				return this._setIO(v);
			}
		},

		stack: {
			lazyAdd: true,
			value: false,
			setter: function(v) {
				return this._setStack(v);
			},
			validator: isBoolean
		},

		title: {
			value: BLANK,
			validator: isString
		}
	}
});

A.extend(Dialog, A.Overlay, {
	/*
	* Lifecycle
	*/
	renderUI: function () {
		var instance = this;

		instance._renderElements();
	},

	bindUI: function () {
		var instance = this;

		instance._bindElements();
	},

	renderer: function() {
		var instance = this;

		Dialog.superclass.renderer.apply(instance, arguments);

		instance._afterRenderer();
	},

	destructor: function() {
		var instance = this;

		if (instance.OverlayManager) {
			instance.OverlayManager.destroy();
		}

		instance.get(BOUNDING_BOX).remove();
	},

	/*
	* Methods
	*/
	_bindElements: function () {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);
		var closeIconContainter = instance.closeIconContainter;

		var closeFn = function(event) {
			var method = { mouseover: ADD_CLASS, mouseout: REMOVE_CLASS }[event.type];
			event.currentTarget[method](CSS_STATE_HOVER);
		};

		closeIconContainter.on('mouseover', closeFn);
		closeIconContainter.on('mouseout', closeFn);

		closeIconContainter.on('click', function(event) {
			instance.hide();
			instance.fire('close');
		});

		boundingBox.on('mousedown', function() {
			if (instance.OverlayManager) {
				instance.OverlayManager.bringToTop();
			}

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

		instance.after('titleChange', this._afterSetTitle);
	},

	_renderElements: function() {
		var instance = this;

		instance.titleContainter = A.Node.create('

');
		instance.closeIconContainter = A.Node.create('');
		instance.closeIcon = A.Node.create('');

		var closeIcon = instance.closeIcon;
		var closeIconContainter = instance.closeIconContainter;
		var title = instance.get(TITLE);
		var titleContainter = instance.titleContainter;

		closeIcon.addClass(CSS_ICON);
		closeIcon.addClass(CSS_ICON_CLOSE);
		closeIconContainter.addClass(CSS_DIALOG_CLOSE);
		closeIconContainter.addClass(CSS_STATE_DEFAULT);
		closeIconContainter.addClass(CSS_TOOL);
		titleContainter.addClass(CSS_DIALOG_TITLE);

		instance.titleContainter.set(INNER_HTML, title);
	},

	_afterRenderer: function() {
		var instance = this;
		var headerNode = instance.headerNode;
		var stack = instance.get(STACK);
		var closeIconContainter = instance.closeIconContainter;

		headerNode.addClass(CSS_STATE_DEFAULT);

		headerNode.append(instance.titleContainter);
		headerNode.append(closeIconContainter);
		closeIconContainter.append(instance.closeIcon);

		instance._initButtons();

		// forcing lazyAdd:true attrs call the setter
		instance.get(DRAGGABLE);
		instance.get(IO);
	},

	_initButtons: function() {
		var instance = this;
		var buttons = instance.get(BUTTONS);
		var container = A.Node.create('

');
		var nodeModel = A.Node.create('<button></button>');

		container.addClass(CSS_DIALOG_BUTTON_CONTAINER);
		nodeModel.addClass(CSS_DIALOG_BUTTON);

		A.each(buttons, function(button, i) {
			var node = nodeModel.cloneNode();

			if (button.isDefault) {
				node.addClass(CSS_DIALOG_BUTTON_DEFAULT);
			}

			if (button.handler) {
				node.on('click', A.bind(button.handler, instance));
			}

			node.set(INNER_HTML, button.text || BLANK);

			container.append(node);
		});

		if (buttons.length) {
			instance.set(FOOTER_CONTENT, container);
		}
	},

	_setDraggable: function(value) {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);

		var destroyDraggable = function() {
			var dragInstance = instance.get(DRAG_INSTANCE);

			if (dragInstance) {
				// TODO - YUI3 has a bug when destroy and recreates
				dragInstance.destroy();
				dragInstance.unplug(A.Plugin.DDConstrained);
			}
		};

		AUI().use('dd-constrain', function(A) {
			A.DD.DDM.CSS_PREFIX = CSS_PREFIX;

			if (value) {
				var defaults = {
					node: boundingBox,
					handles: [ DOT + CSS_WIDGET_HD ]
				};
				var dragOptions = A.merge(defaults, instance.get(DRAGGABLE) || {});

				// change the drag scope callback to execute using the dialog scope
				if (dragOptions.on) {
					A.each(dragOptions.on, function(fn, eventName) {
						dragOptions.on[eventName] = A.bind(fn, instance);
					});
				}

				destroyDraggable();

				var dragInstance = new A.DD.Drag(dragOptions);

				dragInstance.plug(A.Plugin.DDConstrained, {
					constrain2view: instance.get(CONSTRAIN_TO_VIEWPORT)
				});

				instance.set(DRAG_INSTANCE, dragInstance);
			}
			else {
				destroyDraggable();
			}
		});

		return value;
	},

	_setIO: function(value){
		var instance = this;

		if (value && !instance.get(BODY_CONTENT)) {
			instance.set(BODY_CONTENT, TPL_LOADING);
		}

		AUI().use('io-stdmod', function(A) {
			if (value) {
				instance.unplug(A.Plugin.StdModIOPlugin);

				value.uri = value.uri || value.url;

				value.cfg = A.merge({
					method: POST
				},
				value.cfg);

				var data = value.cfg.data;

				if (typeof data == 'object') {
					value.cfg.data = A.toQueryString(data);
				}

				instance.plug(A.Plugin.StdModIOPlugin, value);

				if (instance.io) {
					instance.io.refresh();
				}
			}
			else {
				instance.unplug(A.Plugin.StdModIOPlugin);
			}
		});

		return value;
	},

	_setStack: function(value) {
		var instance = this;

		AUI().use('overlay-manager', function(A) {
			if (value) {
				instance.unplug(A.Plugin.OverlayManager);

				instance.plug(A.Plugin.OverlayManager, {
					group: instance.get(GROUP)
				});
			}
			else {
				instance.unplug(A.Plugin.OverlayManager);
			}
		});

		return value;
	},

	/*
	* Attribute Listeners
	*/
	_afterSetTitle: function(event) {
		var instance = this;

		instance.titleContainter.set(INNER_HTML, event.newVal);
	}
});

A.Dialog = Dialog;

}, '@VERSION', { requires: [ 'overlay', 'plugin' ], use: [ 'dd-constrain', 'overlay-manager', 'io-stdmod' ] });<|endoftext|>


<commit_before>AUI.add('dialog', function(A) {

var L = A.Lang,
	isBoolean = L.isBoolean,
	isNumber = L.isNumber,
	isString = L.isString,
	isArray = L.isArray,
	isObject = L.isObject,

	ADD_CLASS = 'addClass',
	ANCHOR = 'a',
	BLANK = '',
	BODY_CONTENT = 'bodyContent',
	BOUNDING_BOX = 'boundingBox',
	BUTTON = 'button',
	BUTTONS = 'buttons',
	CLOSE = 'close',
	CONSTRAIN_TO_VIEWPORT = 'constrain2view',
	CONTAINER = 'container',
	CONTENT_BOX = 'contentBox',
	DD = 'dd',
	DEFAULT = 'default',
	DESTROY_ON_CLOSE = 'destroyOnClose',
	DIALOG = 'dialog',
	DOT = '.',
	DRAGGABLE = 'draggable',
	DRAG_INSTANCE = 'dragInstance',
	FOOTER_CONTENT = 'footerContent',
	GROUP = 'group',
	HD = 'hd',
	HEADER = 'header',
	HEADER_CONTENT = 'headerContent',
	HOVER = 'hover',
	ICON = 'icon',
	INNER_HTML = 'innerHTML',
	IO = 'io',
	LOADING = 'loading',
	POST = 'POST',
	REMOVE_CLASS = 'removeClass',
	STACK = 'stack',
	STATE = 'state',
	TITLE = 'title',
	WIDGET = 'widget',

	getCN = A.ClassNameManager.getClassName,

	CSS_DIALOG_BUTTON = getCN(DIALOG, BUTTON),
	CSS_DIALOG_BUTTON_CONTAINER = getCN(DIALOG, BUTTON, CONTAINER),
	CSS_DIALOG_BUTTON_DEFAULT = getCN(DIALOG, BUTTON, DEFAULT),
	CSS_DIALOG_CLOSE = getCN(DIALOG, CLOSE),
	CSS_DIALOG_TITLE = getCN(DIALOG, TITLE),
	CSS_ICON = getCN(ICON),
	CSS_ICON_CLOSE = getCN(ICON, CLOSE),
	CSS_ICON_LOADING = getCN(ICON, LOADING),
	CSS_PREFIX = getCN(DD),
	CSS_STATE_DEFAULT = getCN(STATE, DEFAULT),
	CSS_STATE_HOVER = getCN(STATE, HOVER),
	CSS_WIDGET_HD = getCN(WIDGET, HD),

	TPL_LOADING = '

';

function Dialog(config) {
	Dialog.superclass.constructor.apply(this, arguments);
}

A.mix(Dialog, {
	NAME: DIALOG,

	ATTRS: {
		buttons: {
			value: [],
			validator: isArray
		},

		constrain2view: {
			value: true,
			validator: isBoolean
		},

		destroyOnClose: {
			value: false,
			validator: isBoolean
		},

		draggable: {
			lazyAdd: true,
			value: true,
			setter: function(v) {
				return this._setDraggable(v);
			}
		},

		dragInstance: {
			value: null
		},

		group: {
			value: DEFAULT,
			validator: isString
		},

		headerContent: {
			writeOnce: true,
			getter: function() {
				return this.titleContainter;
			}
		},

		io: {
			lazyAdd: true,
			value: null,
			setter: function(v) {
				return this._setIO(v);
			}
		},

		stack: {
			lazyAdd: true,
			value: true,
			setter: function(v) {
				return this._setStack(v);
			},
			validator: isBoolean
		},

		title: {
			value: BLANK,
			validator: isString
		}
	}
});

A.extend(Dialog, A.Overlay, {
	/*
	* Lifecycle
	*/
	renderUI: function () {
		var instance = this;

		instance._renderElements();
	},

	bindUI: function () {
		var instance = this;

		instance._bindElements();
	},

	renderer: function() {
		var instance = this;

		Dialog.superclass.renderer.apply(instance, arguments);

		instance._afterRenderer();
	},

	destructor: function() {
		var instance = this;

		if (instance.OverlayManager) {
			instance.OverlayManager.destroy();
		}

		instance.get(BOUNDING_BOX).remove();
	},

	/*
	* Methods
	*/
	_bindElements: function () {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);

		instance.closeIcon.on(
			'click',
			function(event) {
				if (instance.get(DESTROY_ON_CLOSE)) {
					instance.destroy();
				}
				else {
					instance.hide();
				}

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

		boundingBox.on('mousedown', function() {
			if (instance.OverlayManager) {
				instance.OverlayManager.bringToTop();
			}

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

		instance.after('titleChange', this._afterSetTitle);
	},

	_renderElements: function() {
		var instance = this;

		instance.titleContainter = A.Node.create('

');

		var closeIcon = new A.ToolItem(CLOSE);

		closeIcon.get('node').addClass(CSS_DIALOG_CLOSE);

		instance.closeIcon = closeIcon;

		var title = instance.get(TITLE);
		var titleContainter = instance.titleContainter;

		titleContainter.addClass(CSS_DIALOG_TITLE);

		titleContainter.html(title);
	},

	_afterRenderer: function() {
		var instance = this;
		var headerNode = instance.headerNode;
		var stack = instance.get(STACK);

		headerNode.addClass(CSS_STATE_DEFAULT);

		headerNode.append(instance.titleContainter);

		instance.closeIcon.render(headerNode);

		instance._initButtons();

		// forcing lazyAdd:true attrs call the setter
		instance.get(DRAGGABLE);
		instance.get(IO);
	},

	_initButtons: function() {
		var instance = this;
		var buttons = instance.get(BUTTONS);
		var container = A.Node.create('

');
		var nodeModel = A.Node.create('<button></button>');

		container.addClass(CSS_DIALOG_BUTTON_CONTAINER);
		nodeModel.addClass(CSS_DIALOG_BUTTON);

		A.each(buttons, function(button, i) {
			var node = nodeModel.cloneNode();

			if (button.isDefault) {
				node.addClass(CSS_DIALOG_BUTTON_DEFAULT);
			}

			if (button.handler) {
				node.on('click', A.bind(button.handler, instance));
			}

			node.html(button.text || BLANK);

			container.append(node);
		});

		if (buttons.length) {
			instance.set(FOOTER_CONTENT, container);
		}
	},

	_setDraggable: function(value) {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);

		var destroyDraggable = function() {
			var dragInstance = instance.get(DRAG_INSTANCE);

			if (dragInstance) {
				// TODO - YUI3 has a bug when destroy and recreates
				dragInstance.destroy();
				dragInstance.unplug(A.Plugin.DDConstrained);
			}
		};

		A.DD.DDM.CSS_PREFIX = CSS_PREFIX;

		if (value) {
			var defaults = {
				node: boundingBox,
				handles: [ DOT + CSS_WIDGET_HD ]
			};
			var dragOptions = A.merge(defaults, instance.get(DRAGGABLE) || {});

			// change the drag scope callback to execute using the dialog scope
			if (dragOptions.on) {
				A.each(dragOptions.on, function(fn, eventName) {
					dragOptions.on[eventName] = A.bind(fn, instance);
				});
			}

			destroyDraggable();

			var dragInstance = new A.DD.Drag(dragOptions);

			dragInstance.plug(A.Plugin.DDConstrained, {
				constrain2view: instance.get(CONSTRAIN_TO_VIEWPORT)
			});

			instance.set(DRAG_INSTANCE, dragInstance);
		}
		else {
			destroyDraggable();
		}

		return value;
	},

	_setIO: function(value) {
		var instance = this;

		if (value && !instance.get(BODY_CONTENT)) {
			instance.set(BODY_CONTENT, TPL_LOADING);
		}

		if (value) {
			instance.unplug(A.Plugin.StdModIOPlugin);

			value.uri = value.uri || value.url;
			value.cfg = value.cfg || {};

			var data = value.cfg.data;

			if (isObject(data)) {
				value.cfg.data = A.toQueryString(data);
			}

			instance.plug(A.Plugin.StdModIOPlugin, value);

			var autoRefresh = ('autoRefresh' in value) ? value.autoRefresh : true;

			if (instance.io && autoRefresh) {
				instance.io.refresh();
			}
		}
		else {
			instance.unplug(A.Plugin.StdModIOPlugin);
		}

		return value;
	},

	_setStack: function(value) {
		var instance = this;

		if (value) {
			instance.unplug(A.Plugin.OverlayManager);

			instance.plug(A.Plugin.OverlayManager, {
				group: instance.get(GROUP),
				zIndexBase: 1000
			});
		}
		else {
			instance.unplug(A.Plugin.OverlayManager);
		}

		return value;
	},

	/*
	* Attribute Listeners
	*/
	_afterSetTitle: function(event) {
		var instance = this;

		instance.titleContainter.html(event.newVal);
	}
});

A.Dialog = Dialog;

}, '@VERSION', { requires: [ 'aui-base', 'overlay-manager', 'dd-constrain', 'io-stdmod', 'dialog-css' ] });<commit_msg>Dialog added .close() method<commit_after>AUI.add('dialog', function(A) {

var L = A.Lang,
	isBoolean = L.isBoolean,
	isNumber = L.isNumber,
	isString = L.isString,
	isArray = L.isArray,
	isObject = L.isObject,

	ADD_CLASS = 'addClass',
	ANCHOR = 'a',
	BLANK = '',
	BODY_CONTENT = 'bodyContent',
	BOUNDING_BOX = 'boundingBox',
	BUTTON = 'button',
	BUTTONS = 'buttons',
	CLOSE = 'close',
	CONSTRAIN_TO_VIEWPORT = 'constrain2view',
	CONTAINER = 'container',
	CONTENT_BOX = 'contentBox',
	DD = 'dd',
	DEFAULT = 'default',
	DESTROY_ON_CLOSE = 'destroyOnClose',
	DIALOG = 'dialog',
	DOT = '.',
	DRAGGABLE = 'draggable',
	DRAG_INSTANCE = 'dragInstance',
	FOOTER_CONTENT = 'footerContent',
	GROUP = 'group',
	HD = 'hd',
	HEADER = 'header',
	HEADER_CONTENT = 'headerContent',
	HOVER = 'hover',
	ICON = 'icon',
	INNER_HTML = 'innerHTML',
	IO = 'io',
	LOADING = 'loading',
	POST = 'POST',
	REMOVE_CLASS = 'removeClass',
	STACK = 'stack',
	STATE = 'state',
	TITLE = 'title',
	WIDGET = 'widget',

	getCN = A.ClassNameManager.getClassName,

	CSS_DIALOG_BUTTON = getCN(DIALOG, BUTTON),
	CSS_DIALOG_BUTTON_CONTAINER = getCN(DIALOG, BUTTON, CONTAINER),
	CSS_DIALOG_BUTTON_DEFAULT = getCN(DIALOG, BUTTON, DEFAULT),
	CSS_DIALOG_CLOSE = getCN(DIALOG, CLOSE),
	CSS_DIALOG_TITLE = getCN(DIALOG, TITLE),
	CSS_ICON = getCN(ICON),
	CSS_ICON_CLOSE = getCN(ICON, CLOSE),
	CSS_ICON_LOADING = getCN(ICON, LOADING),
	CSS_PREFIX = getCN(DD),
	CSS_STATE_DEFAULT = getCN(STATE, DEFAULT),
	CSS_STATE_HOVER = getCN(STATE, HOVER),
	CSS_WIDGET_HD = getCN(WIDGET, HD),

	TPL_LOADING = '

';

function Dialog(config) {
	Dialog.superclass.constructor.apply(this, arguments);
}

A.mix(Dialog, {
	NAME: DIALOG,

	ATTRS: {
		buttons: {
			value: [],
			validator: isArray
		},

		constrain2view: {
			value: true,
			validator: isBoolean
		},

		destroyOnClose: {
			value: false,
			validator: isBoolean
		},

		draggable: {
			lazyAdd: true,
			value: true,
			setter: function(v) {
				return this._setDraggable(v);
			}
		},

		dragInstance: {
			value: null
		},

		group: {
			value: DEFAULT,
			validator: isString
		},

		headerContent: {
			writeOnce: true,
			getter: function() {
				return this.titleContainter;
			}
		},

		io: {
			lazyAdd: true,
			value: null,
			setter: function(v) {
				return this._setIO(v);
			}
		},

		stack: {
			lazyAdd: true,
			value: true,
			setter: function(v) {
				return this._setStack(v);
			},
			validator: isBoolean
		},

		title: {
			value: BLANK,
			validator: isString
		}
	}
});

A.extend(Dialog, A.Overlay, {
	/*
	* Lifecycle
	*/
	renderUI: function () {
		var instance = this;

		instance._renderElements();
	},

	bindUI: function () {
		var instance = this;

		instance._bindElements();
	},

	renderer: function() {
		var instance = this;

		Dialog.superclass.renderer.apply(instance, arguments);

		instance._afterRenderer();
	},

	destructor: function() {
		var instance = this;

		if (instance.OverlayManager) {
			instance.OverlayManager.destroy();
		}

		instance.get(BOUNDING_BOX).remove();
	},

	/*
	* Methods
	*/
	close: function() {
		var instance = this;

		if (instance.get(DESTROY_ON_CLOSE)) {
			instance.destroy();
		}
		else {
			instance.hide();
		}

		instance.fire('close');
	},

	_bindElements: function () {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);

		instance.closeIcon.on(
			'click',
			function(event) {
				instance.close();
			}
		);

		boundingBox.on('mousedown', function() {
			if (instance.OverlayManager) {
				instance.OverlayManager.bringToTop();
			}

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

		instance.after('titleChange', this._afterSetTitle);
	},

	_renderElements: function() {
		var instance = this;

		instance.titleContainter = A.Node.create('

');

		var closeIcon = new A.ToolItem(CLOSE);

		closeIcon.get('node').addClass(CSS_DIALOG_CLOSE);

		instance.closeIcon = closeIcon;

		var title = instance.get(TITLE);
		var titleContainter = instance.titleContainter;

		titleContainter.addClass(CSS_DIALOG_TITLE);

		titleContainter.html(title);
	},

	_afterRenderer: function() {
		var instance = this;
		var headerNode = instance.headerNode;
		var stack = instance.get(STACK);

		headerNode.addClass(CSS_STATE_DEFAULT);

		headerNode.append(instance.titleContainter);

		instance.closeIcon.render(headerNode);

		instance._initButtons();

		// forcing lazyAdd:true attrs call the setter
		instance.get(DRAGGABLE);
		instance.get(IO);
	},

	_initButtons: function() {
		var instance = this;
		var buttons = instance.get(BUTTONS);
		var container = A.Node.create('

');
		var nodeModel = A.Node.create('<button></button>');

		container.addClass(CSS_DIALOG_BUTTON_CONTAINER);
		nodeModel.addClass(CSS_DIALOG_BUTTON);

		A.each(buttons, function(button, i) {
			var node = nodeModel.cloneNode();

			if (button.isDefault) {
				node.addClass(CSS_DIALOG_BUTTON_DEFAULT);
			}

			if (button.handler) {
				node.on('click', A.bind(button.handler, instance));
			}

			node.html(button.text || BLANK);

			container.append(node);
		});

		if (buttons.length) {
			instance.set(FOOTER_CONTENT, container);
		}
	},

	_setDraggable: function(value) {
		var instance = this;
		var boundingBox = instance.get(BOUNDING_BOX);

		var destroyDraggable = function() {
			var dragInstance = instance.get(DRAG_INSTANCE);

			if (dragInstance) {
				// TODO - YUI3 has a bug when destroy and recreates
				dragInstance.destroy();
				dragInstance.unplug(A.Plugin.DDConstrained);
			}
		};

		A.DD.DDM.CSS_PREFIX = CSS_PREFIX;

		if (value) {
			var defaults = {
				node: boundingBox,
				handles: [ DOT + CSS_WIDGET_HD ]
			};
			var dragOptions = A.merge(defaults, instance.get(DRAGGABLE) || {});

			// change the drag scope callback to execute using the dialog scope
			if (dragOptions.on) {
				A.each(dragOptions.on, function(fn, eventName) {
					dragOptions.on[eventName] = A.bind(fn, instance);
				});
			}

			destroyDraggable();

			var dragInstance = new A.DD.Drag(dragOptions);

			dragInstance.plug(A.Plugin.DDConstrained, {
				constrain2view: instance.get(CONSTRAIN_TO_VIEWPORT)
			});

			instance.set(DRAG_INSTANCE, dragInstance);
		}
		else {
			destroyDraggable();
		}

		return value;
	},

	_setIO: function(value) {
		var instance = this;

		if (value && !instance.get(BODY_CONTENT)) {
			instance.set(BODY_CONTENT, TPL_LOADING);
		}

		if (value) {
			instance.unplug(A.Plugin.StdModIOPlugin);

			value.uri = value.uri || value.url;
			value.cfg = value.cfg || {};

			var data = value.cfg.data;

			if (isObject(data)) {
				value.cfg.data = A.toQueryString(data);
			}

			instance.plug(A.Plugin.StdModIOPlugin, value);

			var autoRefresh = ('autoRefresh' in value) ? value.autoRefresh : true;

			if (instance.io && autoRefresh) {
				instance.io.refresh();
			}
		}
		else {
			instance.unplug(A.Plugin.StdModIOPlugin);
		}

		return value;
	},

	_setStack: function(value) {
		var instance = this;

		if (value) {
			instance.unplug(A.Plugin.OverlayManager);

			instance.plug(A.Plugin.OverlayManager, {
				group: instance.get(GROUP),
				zIndexBase: 1000
			});
		}
		else {
			instance.unplug(A.Plugin.OverlayManager);
		}

		return value;
	},

	/*
	* Attribute Listeners
	*/
	_afterSetTitle: function(event) {
		var instance = this;

		instance.titleContainter.html(event.newVal);
	}
});

A.Dialog = Dialog;

}, '@VERSION', { requires: [ 'aui-base', 'overlay-manager', 'dd-constrain', 'io-stdmod', 'dialog-css' ] });<|endoftext|>


<commit_before>/** @jsx React.DOM */

var React = require('react');
var SerializablePageDiff = require('../livescript/components/SerializablePageDiff.ls');

console.log('React', React);
console.log('chrome', chrome);

var HelloMessage = React.createClass({
  render: function(){
    return
Hello {this.props.name}
;
  }
});

React.renderComponent(<HelloMessage name="Johnson"/>,
  document.getElementById('body'));

chrome.runtime.onMessage.addListener(function(message){
  switch(message.type){

    // Background script starts processing a CSS or HTML change.
    //
    case "PROCESS_START":
    console.log("<Message> Background script processing started");
    break;

    // The background script has done all processing.
    //
    case "PROCESS_END":
    console.log("<Message> Background script processing end");
    break;

    // The background script passes a SerializablePageDiff instance here.
    case "PAGE_DIFF":
    console.log("<Message> Data arrived from background script", new SerializablePageDiff(message.data));
  }
});
<commit_msg>Expose pageDiff objects for debug<commit_after>/** @jsx React.DOM */

var React = require('react');
var SerializablePageDiff = require('../livescript/components/SerializablePageDiff.ls');

console.log('React', React);
console.log('chrome', chrome);

var HelloMessage = React.createClass({
  render: function(){
    return
Hello {this.props.name}
;
  }
});

React.renderComponent(<HelloMessage name="Jacky"/>,
  document.getElementById('body'));

// For debug.
// TODO: Remove when going live!
//
window.pageDiffs = [];

chrome.runtime.onMessage.addListener(function(message){
  var pageDiff;
  switch(message.type){

    // Background script starts processing a CSS or HTML change.
    //
    case "PROCESS_START":
    console.log("<Message> Background script processing started");
    break;

    // The background script has done all processing.
    //
    case "PROCESS_END":
    console.log("<Message> Background script processing end");
    break;

    // The background script passes a SerializablePageDiff instance here.
    case "PAGE_DIFF":
    pageDiff = new SerializablePageDiff(message.data);
    console.log("<Message> Data arrived from background script", new SerializablePageDiff(message.data));

    // For debug.
    // TODO: Remove when going live!
    //
    pageDiffs.push(pageDiff);
  }
});
<|endoftext|>


<commit_before>(function($) {
  var RangeRover = function () {
    this.options = {
      range: false,
      mode: 'plain',
      autocalculate: true,
      color: '#e8e8e8',
      step: 1
    };
    this.coordinates = {
      startSkate: {
        min: 0,
        max: 0
      },
      endSkate: {
        min: 0,
        max: 0
      }
    };
    this.selector = null;
    this.startSkate = null;
    this.endSkate = null;
    this.progressBar = null;
    // whether mouse/finger pressed or not
    this.enabledSkater = null;
    this.selected = {
      start: {
        value: 0
      }
    };
    this.setEvendHandlers = function () {
      var self = this;

      self.startSkate.on('mousedown touchstart', function() {
        self.enabledSkater = 'startSkate';
      });

      if (self.options.range) {
        self.endSkate.on('mousedown touchstart', function() {
          self.enabledSkater = 'endSkate';
        });
      }

      $(document).on('mouseup touchend', function() {
        self.checkSelection(null);
        self.enabledSkater = null;
      });

      $(document).on('mousemove touchmove', function (e) {
        if (self.enabledSkater) {
          self.checkSelection(null);
          var positionToScroll = e.pageX - self.selector.offset().left;

          if (positionToScroll < self.coordinates[self.enabledSkater].min) {
            // use slider's left border as a min position
            positionToScroll = self.coordinates[self.enabledSkater].min;
          } else if (positionToScroll > self.coordinates[self.enabledSkater].max) {
            // use slider's right border as a max position
            positionToScroll = self.coordinates[self.enabledSkater].max;
          }
          // drag `skate` element if mouse/ finger pressed
          self[self.enabledSkater].css('left', positionToScroll);
        }
      });

      this.progressBar.on('click tap', function (e) {
        self.progressBarSelection(e.pageX);
      });
    };

    this.init = function () {
      var self = this;
      var progressBarContent = [];

      if (this.options.mode === 'plain') {
        self.options.data.size = 100;
        self.options.data = [this.options.data];
      }
      // add specific class to slider to use its width below
      self.selector.addClass('ds-container');
      if (self.options.autocalculate && this.options.mode === 'categorized') {
        RangeRover.autocalculateCategoriesSizes(self.options.data);
      }

      $.each(self.options.data, function(index, category) {
        // set category's percent size and background color to its div
        var exludedValuesPlain = category.exclude ? RangeRover.getExcludedValuesPlain(category) : [];
        var categoryContent = '
' + (category.name ? category.name : '' ) + '' + category.start + '';

        var valuesCount = category.end - category.start - exludedValuesPlain.length;
        // calculate category px width
        var categoryWidth = self.selector.width() / 100 * category.size;
        //  calculate value's px width
        var valueWidth = categoryWidth / valuesCount;

        var j = 0;

        // set first element as a default
        self.selected.start.value = category.start;
        if (self.options.mode === 'categorized') {
          self.selected.start.category = (category.id || category.name);
        }

        for (var i = category.start; i < category.end; i++) {
          j = i;
          if (i + self.options.step - 1 > category.end) {
              j = category.end;
          }
          if (~exludedValuesPlain.indexOf(i)) {
              continue;
          }

          categoryContent += '';
          i = i + self.options.step - 1;
        }
        if (index === self.options.data.length - 1) {
          categoryContent += '' + category.end + '';
          if (self.options.range) {
            self.selected.end = {};
            self.selected.end.value = category.end;
            if (self.options.mode === 'categorized') {
              self.selected.end.category = (category.id || category.name);
            }
          }
        }
        categoryContent += '
';
        progressBarContent.push(categoryContent);
      });

      // put progressBar's with ranges, skate elements to container
      var progressBarHtml = '
' + self.selected.start.value + '

' + progressBarContent.join('') + '
';
      if (this.options.range) {
        progressBarHtml += '
' + self.selected.end.value + '
'
      }

      this.selector.html(progressBarHtml);
      this.startSkate = this.selector.find('.ds-skate');
      if (this.options.range) {
        this.endSkate = this.selector.find('.ds-end-skate');
      }
      this.progressBar = this.selector.find('.ds-progress');
      if (this.options.color) {
        this.progressBar.css('background', this.options.color);
      }
      // prevent browser native drag
      this.selector.attr("ondragstart", 'return false');
      // calculate min left and max right coordinates to use as a border of slider
      this.calculateAndSetCoordinates();
      this.setEvendHandlers();
    };

    this.checkSelection = function (selectedPosition) {
      var selectedValue, selectedCategory;
      var self = this;
      var isTriggeredFromProgressBar = !!selectedPosition;
      var skateChanged = null;

      if (isTriggeredFromProgressBar) {
        if (!self.options.range) {
          skateChanged = 'start';
        }
        if (self.options.range && parseInt(self.endSkate.css('left'), 10) - selectedPosition < selectedPosition - parseInt(self.startSkate.css('left'), 10)) {
          self.endSkate.css('left', selectedPosition);
          skateChanged = 'end';
        } else {
          self.startSkate.css('left', selectedPosition);
          skateChanged = 'start';
        }
      } else {
        if (!self[self.enabledSkater]) {
          return;
        }
        selectedPosition = parseInt(self[self.enabledSkater].css('left'), 10);
      }
      // loop through all items to find selected one
      self.progressBar.find('.ds-item').each(function(index, item) {
        item = $(item);
        var itemLeftOffset = item.offset().left - self.selector.offset().left;
        if (itemLeftOffset <= selectedPosition && itemLeftOffset + item.width() > selectedPosition) {
          selectedValue = +item.attr('data-year');
          selectedCategory = item.parent().attr('data-category');
          return false;
        }
      });
      skateChanged = skateChanged || (self.enabledSkater ? self.enabledSkater.split('Skate')[0] : null);
      // update selectedValue and call onChange if selectedYear has been changed

      if (selectedValue && selectedValue !== this.selected[skateChanged].value) {
        self.selected[skateChanged].value = +selectedValue;

        if (self.options.mode === 'categorized') {
          self.selected[skateChanged].category = selectedCategory;
        }
        self.updateSelectedLabels();
        if (self.options.onChange && typeof self.options.onChange === 'function') {
          self.onChange();
        }
      }
    };

    this.onChange = function () {
      this.options.onChange(this.selected);
    };

    this.progressBarSelection = function (pageX) {
      this.checkSelection(pageX - $('.ds-container').offset().left);
    };

    this.updateSelectedLabels = function () {
      this.updateCoordinates();
      this.startSkate.children('.ds-skate-year-mark').html(this.selected.start.value);

      if (this.options.range) {
        this.endSkate.children('.ds-skate-year-mark').html(this.selected.end.value);
      }
    };

    this.updateCoordinates = function () {
      if (this.options.range) {
        this.coordinates.startSkate.max = parseInt(this.endSkate.css('left'), 10);
        this.coordinates.endSkate.min = parseInt(this.startSkate.css('left'), 10);
      }
    };

    this.calculateAndSetCoordinates = function () {
      this.coordinates.startSkate.max = this.selector.width() - this.startSkate.width() - parseInt(this.startSkate.css('border-width'), 10);

      if (this.options.range) {
        this.coordinates.endSkate.max = this.selector.width() - this.endSkate.width() - parseInt(this.endSkate.css('border-width'), 10);
      }
    };

    this.select = function (year) {
      if (year !== this.selectedYear) {
        var yearElement = $('.ds-category-item[data-year="' + year + '"]');
        if (!yearElement.length) {
          console.warn('RangeRover -> select: element `' + year + '` is not found.');
          return this;
        }
        var leftPosition = yearElement.offset().left;
        this.skate.css('left', leftPosition);
        this.selectedYear = year;
        this.updateSelectedYear();

        if (this.options.onChange && typeof this.options.onChange === 'function') {
          this.onChange();
        }
      }
      return this;
    }
  };

  RangeRover.autocalculateCategoriesSizes = function (categories) {
    var totalCount = categories.reduce(function(prev, next, index) {
      if (index === 1) {
        return (prev.end - prev.start) + (next.end - next.start);
      } else {
        return prev + (next.end - next.start);
      }
    });
    return categories.map(function(e) {
        e.size = 100 / totalCount * (e.end - e.start);
    });
  };

  RangeRover.getExcludedValuesPlain = function (category) {
    var plainYears = [];
    $.each(category.exclude, function (index, y) {
      if (typeof y === 'object' && y.start && y.end) {
        for (var i = y.start; i <= y.end; i++) {
          plainYears.push(i);
        }
      } else {
        plainYears.push(y);
      }
    });
    return plainYears;
  };

  RangeRover.isArray = function (obj) {
		if (Object.prototype.toString.call(obj) === '[object Array]') {
			return true;
		}
	};

  $.fn.extend({
    rangeRover: function (options) {
      var slider = new RangeRover();
      slider.options = $.extend(slider.options, options);

      if (!slider.options.data || RangeRover.isArray(slider.options.data) && !slider.options.data.length) {
        console.warn('RangeRover -> please provide data');
        return;
      }

      slider.selector = $(this);
      slider.init();

      if (options.onInit && typeof options.onInit === 'function') {
        options.onInit();
      }
      return slider;
    }
  });
})(jQuery);
<commit_msg>Improve error handling<commit_after>(function($) {
  var RangeRover = function () {
    this.options = {
      range: false,
      mode: 'plain',
      autocalculate: true,
      color: '#e8e8e8',
      step: 1
    };
    this.coordinates = {
      startSkate: {
        min: 0,
        max: 0
      },
      endSkate: {
        min: 0,
        max: 0
      }
    };
    this.selector = null;
    this.startSkate = null;
    this.endSkate = null;
    this.progressBar = null;
    // whether mouse/finger pressed or not
    this.enabledSkater = null;
    this.selected = {
      start: {
        value: 0
      }
    };
    this.setEvendHandlers = function () {
      var self = this;

      self.startSkate.on('mousedown touchstart', function() {
        self.enabledSkater = 'startSkate';
      });

      if (self.options.range) {
        self.endSkate.on('mousedown touchstart', function() {
          self.enabledSkater = 'endSkate';
        });
      }

      $(document).on('mouseup touchend', function() {
        self.checkSelection(null);
        self.enabledSkater = null;
      });

      $(document).on('mousemove touchmove', function (e) {
        if (self.enabledSkater) {
          self.checkSelection(null);
          var positionToScroll = e.pageX - self.selector.offset().left;

          if (positionToScroll < self.coordinates[self.enabledSkater].min) {
            // use slider's left border as a min position
            positionToScroll = self.coordinates[self.enabledSkater].min;
          } else if (positionToScroll > self.coordinates[self.enabledSkater].max) {
            // use slider's right border as a max position
            positionToScroll = self.coordinates[self.enabledSkater].max;
          }
          // drag `skate` element if mouse/ finger pressed
          self[self.enabledSkater].css('left', positionToScroll);
        }
      });

      this.progressBar.on('click tap', function (e) {
        self.progressBarSelection(e.pageX);
      });
    };

    this.init = function () {
      var self = this;
      var progressBarContent = [];

      if (this.options.mode === 'plain') {
        self.options.data.size = 100;
        self.options.data = [this.options.data];
      }
      // add specific class to slider to use its width below
      self.selector.addClass('ds-container');
      if (self.options.autocalculate && this.options.mode === 'categorized') {
        RangeRover.autocalculateCategoriesSizes(self.options.data);
      }

      $.each(self.options.data, function(index, category) {
        // set category's percent size and background color to its div
        var exludedValuesPlain = category.exclude ? RangeRover.getExcludedValuesPlain(category) : [];
        var categoryContent = '
' + (category.name ? category.name : '' ) + '' + category.start + '';

        var valuesCount = category.end - category.start - exludedValuesPlain.length;
        // calculate category px width
        var categoryWidth = self.selector.width() / 100 * category.size;
        //  calculate value's px width
        var valueWidth = categoryWidth / valuesCount;

        var j = 0;

        // set first element as a default
        self.selected.start.value = category.start;
        if (self.options.mode === 'categorized') {
          self.selected.start.category = (category.id || category.name);
        }

        for (var i = category.start; i < category.end; i++) {
          j = i;
          if (i + self.options.step - 1 > category.end) {
              j = category.end;
          }
          if (~exludedValuesPlain.indexOf(i)) {
              continue;
          }

          categoryContent += '';
          i = i + self.options.step - 1;
        }
        if (index === self.options.data.length - 1) {
          categoryContent += '' + category.end + '';
          if (self.options.range) {
            self.selected.end = {};
            self.selected.end.value = category.end;
            if (self.options.mode === 'categorized') {
              self.selected.end.category = (category.id || category.name);
            }
          }
        }
        categoryContent += '
';
        progressBarContent.push(categoryContent);
      });

      // put progressBar's with ranges, skate elements to container
      var progressBarHtml = '
' + self.selected.start.value + '

' + progressBarContent.join('') + '
';
      if (this.options.range) {
        progressBarHtml += '
' + self.selected.end.value + '
'
      }

      this.selector.html(progressBarHtml);
      this.startSkate = this.selector.find('.ds-skate');
      if (this.options.range) {
        this.endSkate = this.selector.find('.ds-end-skate');
      }
      this.progressBar = this.selector.find('.ds-progress');
      if (this.options.color) {
        this.progressBar.css('background', this.options.color);
      }
      // prevent browser native drag
      this.selector.attr("ondragstart", 'return false');
      // calculate min left and max right coordinates to use as a border of slider
      this.calculateAndSetCoordinates();
      this.setEvendHandlers();
    };

    this.checkSelection = function (selectedPosition) {
      var selectedValue, selectedCategory;
      var self = this;
      var isTriggeredFromProgressBar = !!selectedPosition;
      var skateChanged = null;

      if (isTriggeredFromProgressBar) {
        if (!self.options.range) {
          skateChanged = 'start';
        }
        if (self.options.range && parseInt(self.endSkate.css('left'), 10) - selectedPosition < selectedPosition - parseInt(self.startSkate.css('left'), 10)) {
          self.endSkate.css('left', selectedPosition);
          skateChanged = 'end';
        } else {
          self.startSkate.css('left', selectedPosition);
          skateChanged = 'start';
        }
      } else {
        if (!self[self.enabledSkater]) {
          return;
        }
        selectedPosition = parseInt(self[self.enabledSkater].css('left'), 10);
      }
      // loop through all items to find selected one
      self.progressBar.find('.ds-item').each(function(index, item) {
        item = $(item);
        var itemLeftOffset = item.offset().left - self.selector.offset().left;
        if (itemLeftOffset <= selectedPosition && itemLeftOffset + item.width() > selectedPosition) {
          selectedValue = +item.attr('data-year');
          selectedCategory = item.parent().attr('data-category');
          return false;
        }
      });
      skateChanged = skateChanged || (self.enabledSkater ? self.enabledSkater.split('Skate')[0] : null);
      // update selectedValue and call onChange if selectedYear has been changed

      if (selectedValue && selectedValue !== this.selected[skateChanged].value) {
        self.selected[skateChanged].value = +selectedValue;

        if (self.options.mode === 'categorized') {
          self.selected[skateChanged].category = selectedCategory;
        }
        self.updateSelectedLabels();
        if (self.options.onChange && typeof self.options.onChange === 'function') {
          self.onChange();
        }
      }
    };

    this.onChange = function () {
      this.options.onChange(this.selected);
    };

    this.progressBarSelection = function (pageX) {
      this.checkSelection(pageX - $('.ds-container').offset().left);
    };

    this.updateSelectedLabels = function () {
      this.updateCoordinates();
      this.startSkate.children('.ds-skate-year-mark').html(this.selected.start.value);

      if (this.options.range) {
        this.endSkate.children('.ds-skate-year-mark').html(this.selected.end.value);
      }
    };

    this.updateCoordinates = function () {
      if (this.options.range) {
        this.coordinates.startSkate.max = parseInt(this.endSkate.css('left'), 10);
        this.coordinates.endSkate.min = parseInt(this.startSkate.css('left'), 10);
      }
    };

    this.calculateAndSetCoordinates = function () {
      this.coordinates.startSkate.max = this.selector.width() - this.startSkate.width() - parseInt(this.startSkate.css('border-width'), 10);

      if (this.options.range) {
        this.coordinates.endSkate.max = this.selector.width() - this.endSkate.width() - parseInt(this.endSkate.css('border-width'), 10);
      }
    };

    this.select = function (year) {
      if (year !== this.selectedYear) {
        var yearElement = $('.ds-category-item[data-year="' + year + '"]');
        if (!yearElement.length) {
          console.warn('RangeRover -> select: element `' + year + '` is not found.');
          return this;
        }
        var leftPosition = yearElement.offset().left;
        this.skate.css('left', leftPosition);
        this.selectedYear = year;
        this.updateSelectedYear();

        if (this.options.onChange && typeof this.options.onChange === 'function') {
          this.onChange();
        }
      }
      return this;
    }
  };

  RangeRover.autocalculateCategoriesSizes = function (categories) {
    var totalCount = categories.reduce(function(prev, next, index) {
      if (index === 1) {
        return (prev.end - prev.start) + (next.end - next.start);
      } else {
        return prev + (next.end - next.start);
      }
    });
    return categories.map(function(e) {
        e.size = 100 / totalCount * (e.end - e.start);
    });
  };

  RangeRover.getExcludedValuesPlain = function (category) {
    var plainYears = [];
    $.each(category.exclude, function (index, y) {
      if (typeof y === 'object' && y.start && y.end) {
        for (var i = y.start; i <= y.end; i++) {
          plainYears.push(i);
        }
      } else {
        plainYears.push(y);
      }
    });
    return plainYears;
  };

  RangeRover.isArray = function (obj) {
		if (Object.prototype.toString.call(obj) === '[object Array]') {
			return true;
		}
	};

  $.fn.extend({
    rangeRover: function (options) {
      var slider = new RangeRover();
      slider.options = $.extend(slider.options, options);

      if (!slider.options.data || RangeRover.isArray(slider.options.data) && !slider.options.data.length) {
        console.warn('RangeRover -> please provide data');
        return;
      }

      if (slider.options.mode === 'plain' && (RangeRover.isArray(slider.options.data) || typeof slider.options.data != 'object')) {
        console.warn('RangeRover -> `data` must be object in `plain` mode');
        return;
      }

      if (slider.options.mode === 'categorized' && !RangeRover.isArray(slider.options.data)) {
        console.warn('RangeRover -> `data` must be array in `categorized` mode');
        return;
      }

      slider.selector = $(this);
      slider.init();

      if (options.onInit && typeof options.onInit === 'function') {
        options.onInit();
      }
      return slider;
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>// Functions to save and restore geometric state

var attributesToClone = [
    //"_traces", // internal
    //"_traces_index", // internal
    //"_traces_tick", // internal
    "align",
    "alpha",
    "angle", // LineByFixedAngle, may need update once we have inspect
    //"antipodalPoint", // internal, PointOnCircle to OtherPointOnCircle
    "args",
    "arrow",
    "arrowposition",
    "arrowshape",
    "arrowsides",
    "arrowsize",
    //"behavior", // needs dedicated code
    "clip",
    "color",
    "dashtype",
    //"dir", // Through, not needed if we export pos
    //"dock", // needs dedicated code
    "drawtrace",
    //"dualMatrix", // output for conic
    //"endPoint", // output for arc
    //"endpos", // output for segment
    //"farpoint", // output for segment
    "fillalpha",
    "fillcolor",
    "filled", // drawgeoarc
    //"homog", // save as pos
    //"incidences", // internal
    //"index", // should not be used, select by pos
    //"isArc", // internal
    //"isshowing", // internal
    //"kind", // internal
    "labeled",
    "labelpos",
    //"mat1", // output of Möbius transformations
    //"mat2", // output of Möbius transformations
    //"matrix", // output of conic or transform
    //"movable", // internal
    "name",
    "overhang",
    //"param", // internal
    "pinned",
    //"pos", // needs dedicated code
    "printname",
    "radius", // CircleMr, does seem to update this
    //"results", // output of multi-valued operations
    //"rot", // internal, LineByFixedAngle
    //"sclRsq", // internal, TrReflectionC
    "size",
    //"startPoint", // output for arc
    //"startpos", // output for segment
    //"stateIdx", // internal
    "text",
    "text_fontfamily",
    "textbold",
    "textitalics",
    "textsize",
    //"tooClose", // internal
    "tracedim",
    "tracelength",
    "traceskip",
    "tracing",
    "type",
    //"viaPoint", // output for arc
    "visible",
];

function savePos(el) {
    if (!(/^Select/.test(el.type) || geoOps[el.type].isMovable))
        return null; // Fully determined by arguments, no position needed
    var unwrap = General.unwrap;
    var sum = CSNumber.add;
    switch (el.kind) {
        case "P":
        case "L":
        case "Text":
            return unwrap(el.homog);
        case "C":
            var mat = el.matrix.value;
            return {
                xx: unwrap(mat[0].value[0]),
                yy: unwrap(mat[1].value[1]),
                zz: unwrap(mat[2].value[2]),
                xy: unwrap(sum(mat[0].value[1], mat[1].value[0])),
                xz: unwrap(sum(mat[0].value[2], mat[2].value[0])),
                yz: unwrap(sum(mat[1].value[2], mat[2].value[1])),
            };
        default:
            return null;
    }
}

function saveDockingInfo(dock) {
    var res = {};
    res.offset = General.unwrap(dock.offset);
    if (dock.to) res.to = dock.to; // String
    if (dock.corner) res.corner = dock.corner; // String
    return res;
}

function saveGeoElement(el) {
    var res = {};
    attributesToClone.forEach(function(key) {
        if (!el.hasOwnProperty(key)) return;
        var val = General.unwrap(el[key]);
        if (val !== null && val !== undefined)
            res[key] = val;
    });
    var pos = savePos(el);
    if (pos) res.pos = pos;
    if (el.dock) res.dock = saveDockingInfo(el.dock);
    return res;
}

function saveGeoState() {
    var res = [];
    csgeo.gslp.forEach(function(el) {
        if (el.tmp) return;
        res.push(saveGeoElement(el));
    });
    return res;
}

globalInstance.saveState = function() {
    return {
        geometry: saveGeoState(),
    };
};
<commit_msg>Take dimDependent into account when saving colors<commit_after>// Functions to save and restore geometric state

var attributesToClone = [
    //"_traces", // internal
    //"_traces_index", // internal
    //"_traces_tick", // internal
    "align",
    "alpha",
    "angle", // LineByFixedAngle, may need update once we have inspect
    //"antipodalPoint", // internal, PointOnCircle to OtherPointOnCircle
    "args",
    "arrow",
    "arrowposition",
    "arrowshape",
    "arrowsides",
    "arrowsize",
    //"behavior", // needs dedicated code
    "clip",
    "color",
    "dashtype",
    //"dir", // Through, not needed if we export pos
    //"dock", // needs dedicated code
    "drawtrace",
    //"dualMatrix", // output for conic
    //"endPoint", // output for arc
    //"endpos", // output for segment
    //"farpoint", // output for segment
    "fillalpha",
    "fillcolor",
    "filled", // drawgeoarc
    //"homog", // save as pos
    //"incidences", // internal
    //"index", // should not be used, select by pos
    //"isArc", // internal
    //"isshowing", // internal
    //"kind", // internal
    "labeled",
    "labelpos",
    //"mat1", // output of Möbius transformations
    //"mat2", // output of Möbius transformations
    //"matrix", // output of conic or transform
    //"movable", // internal
    "name",
    "overhang",
    //"param", // internal
    "pinned",
    //"pos", // needs dedicated code
    "printname",
    "radius", // CircleMr, does seem to update this
    //"results", // output of multi-valued operations
    //"rot", // internal, LineByFixedAngle
    //"sclRsq", // internal, TrReflectionC
    "size",
    //"startPoint", // output for arc
    //"startpos", // output for segment
    //"stateIdx", // internal
    "text",
    "text_fontfamily",
    "textbold",
    "textitalics",
    "textsize",
    //"tooClose", // internal
    "tracedim",
    "tracelength",
    "traceskip",
    "tracing",
    "type",
    //"viaPoint", // output for arc
    "visible",
];

function savePos(el) {
    if (!(/^Select/.test(el.type) || geoOps[el.type].isMovable))
        return null; // Fully determined by arguments, no position needed
    var unwrap = General.unwrap;
    var sum = CSNumber.add;
    switch (el.kind) {
        case "P":
        case "L":
        case "Text":
            return unwrap(el.homog);
        case "C":
            var mat = el.matrix.value;
            return {
                xx: unwrap(mat[0].value[0]),
                yy: unwrap(mat[1].value[1]),
                zz: unwrap(mat[2].value[2]),
                xy: unwrap(sum(mat[0].value[1], mat[1].value[0])),
                xz: unwrap(sum(mat[0].value[2], mat[2].value[0])),
                yz: unwrap(sum(mat[1].value[2], mat[2].value[1])),
            };
        default:
            return null;
    }
}

function saveDockingInfo(dock) {
    var res = {};
    res.offset = General.unwrap(dock.offset);
    if (dock.to) res.to = dock.to; // String
    if (dock.corner) res.corner = dock.corner; // String
    return res;
}

function saveGeoElement(el) {
    var res = {};
    attributesToClone.forEach(function(key) {
        if (!el.hasOwnProperty(key)) return;
        var val = General.unwrap(el[key]);
        if (val !== null && val !== undefined)
            res[key] = val;
    });
    if (el.kind === "P" && (!el.movable || el.pinned) && res.color) {
        var undim = CSNumber.real(1 / defaultAppearance.dimDependent);
        res.color = General.unwrap(List.scalmult(undim, el.color));
    }
    var pos = savePos(el);
    if (pos) res.pos = pos;
    if (el.dock) res.dock = saveDockingInfo(el.dock);
    return res;
}

function saveGeoState() {
    var res = [];
    csgeo.gslp.forEach(function(el) {
        if (el.tmp) return;
        res.push(saveGeoElement(el));
    });
    return res;
}

globalInstance.saveState = function() {
    return {
        geometry: saveGeoState(),
    };
};
<|endoftext|>


<commit_before>this.mmooc = this.mmooc || {};

this.mmooc.enroll = (function() {
  return {
    changeEnrollConfirmationButton: function() {
      var enrollForm = $('#enroll_form');
      enrollForm
        .find('.btn')
        .text('Gå til mine ' + mmooc.i18n.CoursePlural.toLowerCase());
      enrollForm.find('.btn').attr('href', '/courses');
      enrollForm.find('.btn-primary').hide();
    },
    changeEnrollTitle: function(s) {
      var headline = $('.ic-Login-confirmation__headline');
      headline.text(s);
    },
    getEnrollInformationElement: function() {
      //There might be several p elements, depending on which self registration screen we are on.
      //Only return the first one.
      return $('#enroll_form > p:first');
    },
    getEnrollAction: function() {
      return $('#enroll_form').attr('action');
    },
    changeEnrollInformation: function(from, to) {
      var confirmEnrollmentElement = this.getEnrollInformationElement();
      confirmEnrollmentElement.text(
        confirmEnrollmentElement.text().replace(from, to)
      );
    },
    hideEnrollInformationPolicy: function() {
      var informationPolicy = $('.ic-Self-enrollment-footer__Secondary');
      informationPolicy.hide();
    },
    changeEnrollButton: function() {
      var enrollForm = $('#enroll_form');
      var confirmButton = enrollForm.find('.btn');
      confirmButton.text('Ja takk, jeg vil registrere meg!');
    },
    hideEnrollButton: function() {
      var enrollForm = $('#enroll_form');
      var confirmButton = enrollForm.find('.btn');
      confirmButton.hide();
    },
    isAlreadyEnrolled: function() {
      confirmEnrollmentElement = this.getEnrollInformationElement();
      var i = confirmEnrollmentElement
        .text()
        .indexOf('Du er allerede registrert i');
      if (i == -1) {
        return false;
      }
      return true;
    },
    selectRegisterUserCheckbox: function() {
      //The checkbox is hidden by canvas-enroll.less, but we need to check it to get the right fields to display.
      setTimeout(function() {
        var createNewUserRadioButton = $('#selfEnrollmentAuthRegCreate');
        createNewUserRadioButton.click();
      }, 1000); // set timeout in ms
    },
    updatePrivacyPolicyLinks: function() {
      html = mmooc.util.renderTemplateWithData('enrollprivacypolicy', {
        privacypolicylink: mmooc.settings.privacyPolicyLink
      });
      $("label[for='selfEnrollmentAuthRegLoginAgreeTerms']").html(html);
    },
    isSelfEnrollmentPage: function() {
      var i = this.getEnrollInformationElement()
        .text()
        .indexOf('Du registrerer deg i');
      if (i == -1) {
        return false;
      }
      return true;
    },
    changeEnrollPage: function() {
      this.changeEnrollTitle('Påmelding');
      if (this.isAlreadyEnrolled()) {
        this.changeEnrollConfirmationButton();
      } else {
        this.hideEnrollInformationPolicy();
        if (this.isSelfEnrollmentPage()) {
          //When self enrolling, give the user the impression of registering on the platform, and not on the course
          //we use to make self enrollment possible. See settings.js/selfRegisterCourseCode
          this.getEnrollInformationElement().text('');
          $('#enroll_form > p:nth-child(2)').text(
            'Vennligst fyll inn informasjonen nedenfor for å registrere deg på ' +
              mmooc.settings.platformName
          );
          this.selectRegisterUserCheckbox();
          this.updatePrivacyPolicyLinks();
          this.changeEnrollButton();
        } else {
          this.hideEnrollButton();
          this.changeEnrollInformation(
            'Du registrere deg på ',
            'Vi registrerer deg på ' +
              mmooc.i18n.CourseDefinite.toLowerCase() +
              ' '
          );
          var enrollInformationElement = this.getEnrollInformationElement();
          enrollInformationElement.html(" ");
          var enrollAction = this.getEnrollAction();
          mmooc.api.enrollUser(enrollAction, function(data) {
            $('.loading-gif').remove();
            window.location.href = '/search/all_courses' + mmooc.hrefQueryString;
          });
        }
      }
    },
    printAllCoursesContainer: function() {
      html = mmooc.util.renderTemplateWithData('allcoursescontainer', {
        courseLabel: mmooc.i18n.CoursePlural.toLowerCase(),
        allAvailableCoursesIngress: mmooc.i18n.AllAvailableCoursesIngress,
        linkToMyCourses: mmooc.utilRoot.getLinkToMyCourses()
      });
      document.title = 'Tilgjengelige ' + mmooc.i18n.CoursePlural.toLowerCase();
      document.getElementById('content').innerHTML = html;
    },
    printAllCourses: function() {
      var self = this;
      html = "

";
      $('.mmooc-all-courses-list').append(html);
      mmooc.api.getAllPublicCourses(function(allCourses) {
        mmooc.api.getEnrolledCourses(function(enrolledCourses) {
          var allCoursesWithStatus = mmooc.enroll.setCourseEnrolledStatus(
            allCourses,
            enrolledCourses
          );

          var categorys = mmooc.util.getCourseCategories(allCoursesWithStatus);

          /* If the amount of courses is large, the filter select box and corresponding javascript code in allcoursescontainer.hbs should be enabled

          mmooc.enroll.populateFilter(categorys);

          $("#filter").change(function () {
            mmooc.enroll.applyFilter();
          });

          */

          var coursesCategorized = mmooc.util.getCoursesCategorized(
            allCoursesWithStatus,
            categorys
          );

          $('.mmooc-loader-wrapper').remove();

          for (var i = 0; i < coursesCategorized.length; i++) {
            const coursesCategory = coursesCategorized[i];
            const coursesEnrolledAmount = mmooc.util.filter(
              coursesCategory.courses,
              function(course) {
                return course.enrolled === true
            }).length;
            const coursesAmount = coursesCategory.courses && coursesCategory.courses.length;

            html = mmooc.util.renderTemplateWithData('allcourseslist', {
              queryString: mmooc.hrefQueryString,
              title: coursesCategory.title,
              isAuthenticated: mmooc.util.isAuthenticated(),
              courses: coursesCategory.courses,
              coursesEnrolledAmount: coursesEnrolledAmount,
              coursesAmount: coursesAmount,
              coursesAmountText: mmooc.i18n.CoursesAmount(coursesAmount),
              courseLabel: mmooc.i18n.Course.toLowerCase(),
              goToCourse: mmooc.i18n.GoToCourse,
              courseRegister: mmooc.i18n.CourseRegister,
              courseRegisterFeide: mmooc.i18n.CourseRegisterFeide,
              openCoursesGroupText: mmooc.i18n.OpenCoursesGroup,
              closeCoursesGroupText: mmooc.i18n.CloseCoursesGroup,
              YouAreRegisteredToXCoursesText: mmooc.i18n.YouAreRegisteredToXCourses(coursesEnrolledAmount),
              index: i
            });
            $('.mmooc-all-courses-list').append(html);
            self.createHashTags();
            self.scrollToCourse();
          }

          // Displays information, that there is no current courses available to enroll
          if (coursesCategorized.length == 0) {
            html = '
' + mmooc.i18n.NoCoursesInfo + '
';
            $('.mmooc-all-courses-list').append(html);
          }

          mmooc.enroll.insertModalAndOverlay();
          mmooc.enroll.setClickHandlers();

          // TODO: move if there is a better place for this code - it handles course list UI
          // accordion UI
          $('.mmooc-accordion-header').click(event => {
            let accordionIndex = event.target.getAttribute('index');

            if (
              $(`#mmooc-accordion-header-${accordionIndex}`).hasClass(
                'mmooc-accordion-header-active'
              )
            ) {
              $(`#mmooc-accordion-header-${accordionIndex}`).toggleClass(
                'mmooc-accordion-header-active'
              );
            } else {
              $('.mmooc-accordion-header-active').removeClass(
                'mmooc-accordion-header-active'
              );

              $(`#mmooc-accordion-header-${accordionIndex}`).addClass(
                'mmooc-accordion-header-active'
              );
            }

            // remove active tabs when new accordion element is clicked
            $('.mmooc-tab-head').removeClass('mmooc-tab-head-active');
            $('.mmooc-tab-content').removeClass('mmooc-tab-content-active');
            $('.mmooc-tabs-mobile-header-active').removeClass(
              'mmooc-tabs-mobile-header-active'
            );
            $('.mmooc-tabs-mobile-content-active').removeClass(
              'mmooc-tabs-mobile-content-active'
            );

            // add active class to first tab when the accordion element is opened
            $('.mmooc-tab-head-0').addClass('mmooc-tab-head-active');
            $('.mmooc-tab-content-0').addClass('mmooc-tab-content-active');
          });

          // tabs
          $('.mmooc-tab-head').click(event => {
            let tabIndex = event.target.getAttribute('index');

            $('.mmooc-tab-head').removeClass('mmooc-tab-head-active');
            $(`#mmooc-tab-head-${tabIndex}`).addClass('mmooc-tab-head-active');

            $('.mmooc-tab-content').removeClass('mmooc-tab-content-active');
            $(`#mmooc-tab-content-${tabIndex}`).addClass(
              'mmooc-tab-content-active'
            );
          });

          // tabs-mobile

          $('.mmooc-tabs-mobile-header').click(event => {
            let mobileTabIndex = event.target.getAttribute('index');

            if (
              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).hasClass(
                'mmooc-tabs-mobile-header-active'
              )
            ) {
              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).toggleClass(
                'mmooc-tabs-mobile-header-active'
              );
              $(`#mmooc-tabs-mobile-content-${mobileTabIndex}`).toggleClass(
                'mmooc-tabs-mobile-content-active'
              );
            } else {
              $('.mmooc-tabs-mobile-header-active').removeClass(
                'mmooc-tabs-mobile-header-active'
              );
              $('.mmooc-tabs-mobile-content-active').removeClass(
                'mmooc-tabs-mobile-content-active'
              );

              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).addClass(
                'mmooc-tabs-mobile-header-active'
              );
              $(`#mmooc-tabs-mobile-content-${mobileTabIndex}`).addClass(
                'mmooc-tabs-mobile-content-active'
              );
            }
          });
        });
      });
    },
    createHashTags: function() {
        $('span').click(function(e) {
          if ($(this).filter("[data-name='course']")) {
            var hashTag = $(e.currentTarget).attr("class")
            window.location.hash = hashTag;
          }
        });

        $("button[data-title]").click(function(e){
          var firstCourseId = $(this).siblings().find('span').eq(0).attr('class');
          var hashTag = firstCourseId;
          window.location.hash = hashTag;
        })
    },
    scrollToCourse: function () {
      setTimeout(function() {
        var currentHash = window.location.hash.split('#');
        var courses = $('span').filter("[data-name='course']");

        courses.each(function (i, el) {
          var currentElementId = $(el).attr('class');
          if (currentHash[1] === currentElementId) {
            var categoryElement = $(el).closest('section').find('button[index=0]');
            categoryElement.trigger("click");

            var mobileViewport = window.matchMedia("(max-width: 650px)");

            if(mobileViewport.matches) {
              $([document.documentElement, document.body]).animate({
                scrollTop: $(el).find('button').offset().top
              }, 500);
            }else {
              $([document.documentElement, document.body]).animate({
                scrollTop: $("." + currentElementId).offset().top
              }, 500);
            }
            var courseTab = $(el).find('button');
            courseTab.trigger("click");
          }
        })
      },100)
    },
    setCourseEnrolledStatus: function(allCourses, enrolledCourses) {
      var allCoursesWithStatus = [];
      for (var i = 0; i < allCourses.length; i++) {
        allCourses[i].course.enrolled = false;
        for (var j = 0; j < enrolledCourses.length; j++) {
          if (allCourses[i].course.id == enrolledCourses[j].id) {
            allCourses[i].course.enrolled = true;
          }
        }
        allCoursesWithStatus.push(allCourses[i].course);
      }
      return allCoursesWithStatus;
    },
    insertModalAndOverlay: function() {
      $('body').append("

");
      $('body').append("

");
    },
    handleEnrollClick: function(e, html) {
      $('.mmooc-modal').html(html);
      $('.mmooc-modal-overlay').show();
      $('.mmooc-modal').show();
      $('.mmooc-modal .modal-back').click(function(e) {
        e.preventDefault();
        $('.mmooc-modal-overlay').hide();
        $('.mmooc-modal').hide();
      });
    },
    setClickHandlers: function() {
      $('.notenrolled').click(function(e) {
        e.preventDefault();
        var html = $(this)
          .next()
          .html();
        mmooc.enroll.handleEnrollClick(e, html);
      });
      $('.all-courses-show-modal').click(function(e) {
        e.preventDefault();
        var html = $(this)
          .parent()
          .next()
          .html();
        mmooc.enroll.handleEnrollClick(e, html);
      });
      $('.mmooc-modal-overlay').click(function(e) {
        e.preventDefault();
        $('.mmooc-modal-overlay').hide();
        $('.mmooc-modal').hide();
      });
      $(document).on('keydown', function(e) {
        if (e.keyCode === 27) {
          $('.mmooc-modal-overlay').hide();
          $('.mmooc-modal').hide();
        }
      });
    },
    populateFilter: function(categorys) {
      var options =
        '<option value="Alle">Alle tilgjengelige ' +
        mmooc.i18n.CoursePlural.toLowerCase() +
        '</option>';
      for (var i = 0; i < categorys.length; i++) {
        options +=
          '<option value="' + categorys[i] + '">' + categorys[i] + '</option>';
      }
      $('#filter').append(options);
    },
    applyFilter: function() {
      var value = $('#filter').val();
      if (value == 'Alle') {
        $('.mmooc-all-courses-list').removeClass('filter-active');
        $('.mmooc-all-courses-list h2').each(function() {
          $(this).show();
          $(this)
            .next()
            .show();
        });
      } else {
        $('.mmooc-all-courses-list').addClass('filter-active');
        $('.mmooc-all-courses-list h2').each(function() {
          if ($(this).text() == value) {
            $(this).show();
            $(this)
              .next()
              .show();
          } else {
            $(this).hide();
            $(this)
              .next()
              .hide();
          }
        });
      }
    }
  };
})();
<commit_msg>deep link support for multiple categories<commit_after>this.mmooc = this.mmooc || {};

this.mmooc.enroll = (function() {
  return {
    changeEnrollConfirmationButton: function() {
      var enrollForm = $('#enroll_form');
      enrollForm
        .find('.btn')
        .text('Gå til mine ' + mmooc.i18n.CoursePlural.toLowerCase());
      enrollForm.find('.btn').attr('href', '/courses');
      enrollForm.find('.btn-primary').hide();
    },
    changeEnrollTitle: function(s) {
      var headline = $('.ic-Login-confirmation__headline');
      headline.text(s);
    },
    getEnrollInformationElement: function() {
      //There might be several p elements, depending on which self registration screen we are on.
      //Only return the first one.
      return $('#enroll_form > p:first');
    },
    getEnrollAction: function() {
      return $('#enroll_form').attr('action');
    },
    changeEnrollInformation: function(from, to) {
      var confirmEnrollmentElement = this.getEnrollInformationElement();
      confirmEnrollmentElement.text(
        confirmEnrollmentElement.text().replace(from, to)
      );
    },
    hideEnrollInformationPolicy: function() {
      var informationPolicy = $('.ic-Self-enrollment-footer__Secondary');
      informationPolicy.hide();
    },
    changeEnrollButton: function() {
      var enrollForm = $('#enroll_form');
      var confirmButton = enrollForm.find('.btn');
      confirmButton.text('Ja takk, jeg vil registrere meg!');
    },
    hideEnrollButton: function() {
      var enrollForm = $('#enroll_form');
      var confirmButton = enrollForm.find('.btn');
      confirmButton.hide();
    },
    isAlreadyEnrolled: function() {
      confirmEnrollmentElement = this.getEnrollInformationElement();
      var i = confirmEnrollmentElement
        .text()
        .indexOf('Du er allerede registrert i');
      if (i == -1) {
        return false;
      }
      return true;
    },
    selectRegisterUserCheckbox: function() {
      //The checkbox is hidden by canvas-enroll.less, but we need to check it to get the right fields to display.
      setTimeout(function() {
        var createNewUserRadioButton = $('#selfEnrollmentAuthRegCreate');
        createNewUserRadioButton.click();
      }, 1000); // set timeout in ms
    },
    updatePrivacyPolicyLinks: function() {
      html = mmooc.util.renderTemplateWithData('enrollprivacypolicy', {
        privacypolicylink: mmooc.settings.privacyPolicyLink
      });
      $("label[for='selfEnrollmentAuthRegLoginAgreeTerms']").html(html);
    },
    isSelfEnrollmentPage: function() {
      var i = this.getEnrollInformationElement()
        .text()
        .indexOf('Du registrerer deg i');
      if (i == -1) {
        return false;
      }
      return true;
    },
    changeEnrollPage: function() {
      this.changeEnrollTitle('Påmelding');
      if (this.isAlreadyEnrolled()) {
        this.changeEnrollConfirmationButton();
      } else {
        this.hideEnrollInformationPolicy();
        if (this.isSelfEnrollmentPage()) {
          //When self enrolling, give the user the impression of registering on the platform, and not on the course
          //we use to make self enrollment possible. See settings.js/selfRegisterCourseCode
          this.getEnrollInformationElement().text('');
          $('#enroll_form > p:nth-child(2)').text(
            'Vennligst fyll inn informasjonen nedenfor for å registrere deg på ' +
              mmooc.settings.platformName
          );
          this.selectRegisterUserCheckbox();
          this.updatePrivacyPolicyLinks();
          this.changeEnrollButton();
        } else {
          this.hideEnrollButton();
          this.changeEnrollInformation(
            'Du registrere deg på ',
            'Vi registrerer deg på ' +
              mmooc.i18n.CourseDefinite.toLowerCase() +
              ' '
          );
          var enrollInformationElement = this.getEnrollInformationElement();
          enrollInformationElement.html(" ");
          var enrollAction = this.getEnrollAction();
          mmooc.api.enrollUser(enrollAction, function(data) {
            $('.loading-gif').remove();
            window.location.href = '/search/all_courses' + mmooc.hrefQueryString;
          });
        }
      }
    },
    printAllCoursesContainer: function() {
      html = mmooc.util.renderTemplateWithData('allcoursescontainer', {
        courseLabel: mmooc.i18n.CoursePlural.toLowerCase(),
        allAvailableCoursesIngress: mmooc.i18n.AllAvailableCoursesIngress,
        linkToMyCourses: mmooc.utilRoot.getLinkToMyCourses()
      });
      document.title = 'Tilgjengelige ' + mmooc.i18n.CoursePlural.toLowerCase();
      document.getElementById('content').innerHTML = html;
    },
    printAllCourses: function() {
      var self = this;
      html = "

";
      $('.mmooc-all-courses-list').append(html);
      mmooc.api.getAllPublicCourses(function(allCourses) {
        mmooc.api.getEnrolledCourses(function(enrolledCourses) {
          var allCoursesWithStatus = mmooc.enroll.setCourseEnrolledStatus(
            allCourses,
            enrolledCourses
          );

          var categorys = mmooc.util.getCourseCategories(allCoursesWithStatus);

          /* If the amount of courses is large, the filter select box and corresponding javascript code in allcoursescontainer.hbs should be enabled

          mmooc.enroll.populateFilter(categorys);

          $("#filter").change(function () {
            mmooc.enroll.applyFilter();
          });

          */

          var coursesCategorized = mmooc.util.getCoursesCategorized(
            allCoursesWithStatus,
            categorys
          );

          $('.mmooc-loader-wrapper').remove();

          for (var i = 0; i < coursesCategorized.length; i++) {
            const coursesCategory = coursesCategorized[i];
            const coursesEnrolledAmount = mmooc.util.filter(
              coursesCategory.courses,
              function(course) {
                return course.enrolled === true
            }).length;
            const coursesAmount = coursesCategory.courses && coursesCategory.courses.length;

            html = mmooc.util.renderTemplateWithData('allcourseslist', {
              queryString: mmooc.hrefQueryString,
              title: coursesCategory.title,
              isAuthenticated: mmooc.util.isAuthenticated(),
              courses: coursesCategory.courses,
              coursesEnrolledAmount: coursesEnrolledAmount,
              coursesAmount: coursesAmount,
              coursesAmountText: mmooc.i18n.CoursesAmount(coursesAmount),
              courseLabel: mmooc.i18n.Course.toLowerCase(),
              goToCourse: mmooc.i18n.GoToCourse,
              courseRegister: mmooc.i18n.CourseRegister,
              courseRegisterFeide: mmooc.i18n.CourseRegisterFeide,
              openCoursesGroupText: mmooc.i18n.OpenCoursesGroup,
              closeCoursesGroupText: mmooc.i18n.CloseCoursesGroup,
              YouAreRegisteredToXCoursesText: mmooc.i18n.YouAreRegisteredToXCourses(coursesEnrolledAmount),
              index: i
            });
            $('.mmooc-all-courses-list').append(html);
          }

          // Displays information, that there is no current courses available to enroll
          if (coursesCategorized.length == 0) {
            html = '
' + mmooc.i18n.NoCoursesInfo + '
';
            $('.mmooc-all-courses-list').append(html);
          }

          mmooc.enroll.insertModalAndOverlay();
          mmooc.enroll.setClickHandlers();

          // TODO: move if there is a better place for this code - it handles course list UI
          // accordion UI
          $('.mmooc-accordion-header').click(event => {
            let accordionIndex = event.target.getAttribute('index');

            if (
              $(`#mmooc-accordion-header-${accordionIndex}`).hasClass(
                'mmooc-accordion-header-active'
              )
            ) {
              $(`#mmooc-accordion-header-${accordionIndex}`).toggleClass(
                'mmooc-accordion-header-active'
              );
            } else {
              $('.mmooc-accordion-header-active').removeClass(
                'mmooc-accordion-header-active'
              );

              $(`#mmooc-accordion-header-${accordionIndex}`).addClass(
                'mmooc-accordion-header-active'
              );
            }

            // remove active tabs when new accordion element is clicked
            $('.mmooc-tab-head').removeClass('mmooc-tab-head-active');
            $('.mmooc-tab-content').removeClass('mmooc-tab-content-active');
            $('.mmooc-tabs-mobile-header-active').removeClass(
              'mmooc-tabs-mobile-header-active'
            );
            $('.mmooc-tabs-mobile-content-active').removeClass(
              'mmooc-tabs-mobile-content-active'
            );

            // add active class to first tab when the accordion element is opened
            $('.mmooc-tab-head-0').addClass('mmooc-tab-head-active');
            $('.mmooc-tab-content-0').addClass('mmooc-tab-content-active');
          });

          // tabs
          $('.mmooc-tab-head').click(event => {
            let tabIndex = event.target.getAttribute('index');

            $('.mmooc-tab-head').removeClass('mmooc-tab-head-active');
            $(`#mmooc-tab-head-${tabIndex}`).addClass('mmooc-tab-head-active');

            $('.mmooc-tab-content').removeClass('mmooc-tab-content-active');
            $(`#mmooc-tab-content-${tabIndex}`).addClass(
              'mmooc-tab-content-active'
            );
          });

          // tabs-mobile

          $('.mmooc-tabs-mobile-header').click(event => {
            let mobileTabIndex = event.target.getAttribute('index');

            if (
              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).hasClass(
                'mmooc-tabs-mobile-header-active'
              )
            ) {
              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).toggleClass(
                'mmooc-tabs-mobile-header-active'
              );
              $(`#mmooc-tabs-mobile-content-${mobileTabIndex}`).toggleClass(
                'mmooc-tabs-mobile-content-active'
              );
            } else {
              $('.mmooc-tabs-mobile-header-active').removeClass(
                'mmooc-tabs-mobile-header-active'
              );
              $('.mmooc-tabs-mobile-content-active').removeClass(
                'mmooc-tabs-mobile-content-active'
              );

              $(`#mmooc-tabs-mobile-header-${mobileTabIndex}`).addClass(
                'mmooc-tabs-mobile-header-active'
              );
              $(`#mmooc-tabs-mobile-content-${mobileTabIndex}`).addClass(
                'mmooc-tabs-mobile-content-active'
              );
            }
          });

          self.createHashTags();
          self.scrollToCourse();
        });
      });
    },
    createHashTags: function() {
        $('span').click(function(e) {
          if ($(this).filter("[data-name='course']")) {
            var hashTag = $(e.currentTarget).attr("class")
            window.location.hash = hashTag;
          }
        });

        $("button[data-title]").click(function(e){
          var firstCourseId = $(this).siblings().find('span').eq(0).attr('class');
          var hashTag = firstCourseId;
          window.location.hash = hashTag;
        })
    },
    scrollToCourse: function () {
        var currentHash = window.location.hash.split('#');
        var courses = $('span').filter("[data-name='course']");

        courses.each(function (i, el) {
          var currentElementId = $(el).attr('class');
          if (currentHash[1] === currentElementId) {
            var categoryElement = $(el).closest('section').find('button').eq(0);
            categoryElement.trigger("click");

            var mobileViewport = window.matchMedia("(max-width: 650px)");

            if(mobileViewport.matches) {
              $([document.documentElement, document.body]).animate({
                scrollTop: $(el).find('button').offset().top
              }, 500);
            }else {
              $([document.documentElement, document.body]).animate({
                scrollTop: $("." + currentElementId).offset().top
              }, 500);
            }
            var courseTab = $(el).find('button');
            courseTab.trigger("click");
          }
        })
    },
    setCourseEnrolledStatus: function(allCourses, enrolledCourses) {
      var allCoursesWithStatus = [];
      for (var i = 0; i < allCourses.length; i++) {
        allCourses[i].course.enrolled = false;
        for (var j = 0; j < enrolledCourses.length; j++) {
          if (allCourses[i].course.id == enrolledCourses[j].id) {
            allCourses[i].course.enrolled = true;
          }
        }
        allCoursesWithStatus.push(allCourses[i].course);
      }
      return allCoursesWithStatus;
    },
    insertModalAndOverlay: function() {
      $('body').append("

");
      $('body').append("

");
    },
    handleEnrollClick: function(e, html) {
      $('.mmooc-modal').html(html);
      $('.mmooc-modal-overlay').show();
      $('.mmooc-modal').show();
      $('.mmooc-modal .modal-back').click(function(e) {
        e.preventDefault();
        $('.mmooc-modal-overlay').hide();
        $('.mmooc-modal').hide();
      });
    },
    setClickHandlers: function() {
      $('.notenrolled').click(function(e) {
        e.preventDefault();
        var html = $(this)
          .next()
          .html();
        mmooc.enroll.handleEnrollClick(e, html);
      });
      $('.all-courses-show-modal').click(function(e) {
        e.preventDefault();
        var html = $(this)
          .parent()
          .next()
          .html();
        mmooc.enroll.handleEnrollClick(e, html);
      });
      $('.mmooc-modal-overlay').click(function(e) {
        e.preventDefault();
        $('.mmooc-modal-overlay').hide();
        $('.mmooc-modal').hide();
      });
      $(document).on('keydown', function(e) {
        if (e.keyCode === 27) {
          $('.mmooc-modal-overlay').hide();
          $('.mmooc-modal').hide();
        }
      });
    },
    populateFilter: function(categorys) {
      var options =
        '<option value="Alle">Alle tilgjengelige ' +
        mmooc.i18n.CoursePlural.toLowerCase() +
        '</option>';
      for (var i = 0; i < categorys.length; i++) {
        options +=
          '<option value="' + categorys[i] + '">' + categorys[i] + '</option>';
      }
      $('#filter').append(options);
    },
    applyFilter: function() {
      var value = $('#filter').val();
      if (value == 'Alle') {
        $('.mmooc-all-courses-list').removeClass('filter-active');
        $('.mmooc-all-courses-list h2').each(function() {
          $(this).show();
          $(this)
            .next()
            .show();
        });
      } else {
        $('.mmooc-all-courses-list').addClass('filter-active');
        $('.mmooc-all-courses-list h2').each(function() {
          if ($(this).text() == value) {
            $(this).show();
            $(this)
              .next()
              .show();
          } else {
            $(this).hide();
            $(this)
              .next()
              .hide();
          }
        });
      }
    }
  };
})();
<|endoftext|>