<commit_before>
//*@protected
/**
	Default properties of enyo kinds to concatenate as opposed to
	overwriting. These are automatically used unless explicitly
	removed.
*/
enyo.concat = ["concat", "bindings"];

//*@protected
/**
	Is called during kind-initialization to make sure that any property
	noted to be concatenated will be (must be an array) so that those values
	will not be lost by subclasses overriding that property.
*/
enyo.handleConcatenatedProperties = function (ctor, proto) {
	var properties = enyo.merge(ctor.concat || [], proto.concat || []);
	var prop;
	var right;
	var left;
	while (properties.length) {
		prop = properties.shift();
		left = ctor[prop];
		right = proto[prop];
		if ((left instanceof Array) && (right instanceof Array)) {
			ctor[prop] = enyo.merge(left, right);
			// remove the reference to the property so it will not
			// conflict later
			delete proto[prop];
		}
	}
};

//* @public
/**
	Creates a JavaScript constructor function with a prototype defined by
	_inProps_.

	_enyo.kind_ makes it easy to build a constructor-with-prototype (like a
	class) that has advanced features like prototype-chaining (inheritance).

	A plug-in system is included for extending the abilities of the kind
	generator, and constructors are allowed to perform custom operations when
	subclassed.

	If you make changes to _enyo.kind_, be sure to add or update the appropriate
	[unit tests](https://github.com/enyojs/enyo/tree/master/tools/test/core/tests).

	For more information, see the documentation on
	[Creating Kinds](https://github.com/enyojs/enyo/wiki/Creating-Kinds)
	in the Enyo Developer Guide.
*/
enyo.kind = function(inProps) {
	// kind-name to constructor map could be faulty now that a new kind exists, so we simply destroy the memoizations
	enyo._kindCtors = {};
	// extract 'name' property
	var name = inProps.name || "";
	delete inProps.name;
	// extract 'kind' property
	var hasKind = ("kind" in inProps);
	var kind = inProps.kind;
	delete inProps.kind;
	// establish base class reference
	var base = enyo.constructorForKind(kind);
	var isa = base && base.prototype || null;
	// if we have an explicit kind property with value undefined, we probably
	// tried to reference  a kind that is not yet in scope
	if (hasKind && kind === undefined || base === undefined) {
		var problem = kind === undefined ? 'undefined kind' : 'unknown kind (' + kind + ')';
		throw "enyo.kind: Attempt to subclass an " + problem + ". Check dependencies for [" + (name || "<unnamed>") + "].";
	}
	// make a boilerplate constructor
	var ctor = enyo.kind.makeCtor();
	// semi-reserved word 'constructor' causes problems with Prototype and IE, so we rename it here
	if (inProps.hasOwnProperty("constructor")) {
		inProps._constructor = inProps.constructor;
		delete inProps.constructor;
	}
	// create our prototype
	//ctor.prototype = isa ? enyo.delegate(isa) : {};
	enyo.setPrototype(ctor, isa ? enyo.delegate(isa) : {});

	// there are special cases where a base class has a property
	// that may need to be concatenated with a subclasses implementation
	// as opposed to completely overwriting it...
	enyo.handleConcatenatedProperties(ctor.prototype, inProps);

	// put in our props
	enyo.mixin(ctor.prototype, inProps);
	// alias class name as 'kind' in the prototype
	if (!name && kind && "string" === typeof kind) name = kind;
	// but we actually only need to set this if a new name was used
	// not if it is inheriting from a kind anonymously
	if (name) ctor.prototype.kindName = name;
	// cache superclass constructor
	ctor.prototype.base = base;
	// reference our real constructor
	ctor.prototype.ctor = ctor;
	// support pluggable 'features'
	enyo.forEach(enyo.kind.features, function(fn){ fn(ctor, inProps); });
	// put reference into namespace
	if (!enyo.getPath(name)) enyo.setPath(name, ctor);
	return ctor;
};

/**
	Creates a Singleton

		enyo.singleton({
			kind: Control,
			name: "app.MySingleton",
			published: {
				value: "foo"
			},
			makeSomething: function() {
				//...
			}
		});

		app.MySingleton.makeSomething();
		app.MySingleton.setValue("bar");
*/
enyo.singleton = function(conf, context) {
	// extract 'name' property (the name of our singleton)
	var name = conf.name;
	delete(conf.name);
	// create an unnamed kind and save its constructor's function
	var kind = enyo.kind(conf);
	var inst;
	// create the singleton with the previous name and constructor
	enyo.setPath.call(context || enyo.global, name, (inst = new kind()));
	return inst;
};

//* @protected
enyo.kind.makeCtor = function() {
  return function() {;
		if (!(this instanceof arguments.callee)) {
			throw "enyo.kind: constructor called directly, not using 'new'";
		}

		// two-pass instantiation
		var result;
		var cargs = arguments;
		if (this._constructor) {
			// pure construction
			result = this._constructor.apply(this, arguments);
		}
		// defer initialization until entire constructor chain has finished
		if (this.constructed) {
			// post-constructor initialization
			this.constructed.apply(this, arguments);
		}

		for (var idx = 0; idx < enyo.kind.postConstructors.length; ++idx) {
			enyo.kind.postConstructors[idx].apply(this, cargs);
		}

		if (result) {
			return result;
		}
	};
};

// classes referenced by name can omit this namespace (e.g. "Button" instead of "enyo.Button")
enyo.kind.defaultNamespace = "enyo";

//
// feature hooks for the oop system
//
enyo.kind.features = [];

//*@protected
/**
	Post-initialize functions (after constructor has completed).
*/
enyo.kind.postConstructors = [];

//
// 'inherited' feature
//
enyo.kind.features.push(function(ctor, props) {
	var proto = ctor.prototype;
	if (!proto.inherited) {
		proto.inherited = enyo.kind.inherited;
	}
	if (proto.base) {
		// decorate function properties to support inherited (do this ex post facto so that
		// ctor.prototype is known, relies on elements in props being copied by reference)
		for (var n in props) {
			var p = props[n];
			if (enyo.isFunction(p)) {
				p._inherited = proto.base.prototype[n];
				// FIXME: we used to need some extra values for inherited, then inherited got cleaner
				// but in the meantime we used these values to support logging in Object.
				// For now we support this legacy situation, by suppling logging information here.
				p.nom = proto.kindName + '.' + n + '()';
			}
		}
	}
});

//*@protected
/**
	This method is called by enyo.Object's attempting to
	access super-methods of a parent class (kind) by calling
	_this.inherited(arguments)_ from within a kind method. This
	can only be done safely when there is known to be a super
	class with the same method.
*/
enyo.kind.inherited = function (originals, replacements) {
	// one-off methods are the fast track
	var target = originals.callee;
	var fn = target._inherited;
	// the possible exception are proxied methods being
	// executed from within a container under a different
	// context (shared methods) so we have to check one
	// level up in these cases to ensure we find the correct
	// method
	if (!fn || "function" !== typeof fn) {
		target = target.caller || {};
		fn = target._inherited;
	}
	// regardless of how we got here, just ensure we actually
	// have a function to call or else we throw a console
	// warning to notify developers they are calling a
	// super method that doesn't exist
	if ("function" === typeof fn) {
		return fn.apply(this, replacements? enyo.mixin(originals, replacements): originals);
	} else {
		enyo.warn("enyo.kind.inherited: unable to find requested " +
			"super-method from -> " + originals.callee.nom + " in " + this.kindName);
	}
};

//
// 'statics' feature
//
enyo.kind.features.push(function(ctor, props) {
	// install common statics
	enyo.mixin(ctor, enyo.kind.statics);
	// move props statics to constructor
	if (props.statics) {
		enyo.mixin(ctor, props.statics);
		delete ctor.prototype.statics;
	}
	// allow superclass customization

	var base = ctor.prototype.base;
	while (base) {
		base.subclass(ctor, props);
		base = base.prototype.base;
	}
});

enyo.kind.statics = {
	subclass: function(ctor, props) {
		//enyo.log("subclassing [" + ctor.prototype.kind + "] from [", this.prototype.kind + "]");
	},
	extend: function(props) {
		// make sure to allow concatenated properties to function
		// as expected
		enyo.handleConcatenatedProperties(this.prototype, props);
		enyo.mixin(this.prototype, props);
		// support pluggable 'features'
		var ctor = this;
		enyo.forEach(enyo.kind.features, function(fn){ fn(ctor, props); });
	}
};

//
// factory for kinds identified by strings
//
enyo._kindCtors = {};

enyo.constructorForKind = function(inKind) {
	if (inKind === null || enyo.isFunction(inKind)) {
		// in inKind is a function or explicitly null, then that's ctor, full stop.
		return inKind;
	}
	if (inKind) {
		// use memoized constructor if available...
		var ctor = enyo._kindCtors[inKind];
		if (ctor) {
			return ctor;
		}
		// otherwise look it up and memoize what we find
		//
		// if inKind is an object in enyo, say "Control", then ctor = enyo["Control"]
		// if inKind is a path under enyo, say "Heritage.Button", then ctor = enyo["Heritage.Button"] || enyo.Heritage.Button
		// if inKind is a fully qualified path, say "enyo.Heritage.Button", then ctor = enyo["enyo.Heritage.Button"] || enyo.enyo.Heritage.Button || enyo.Heritage.Button
		//
		// Note that kind "Foo" will resolve to enyo.Foo before resolving to global "Foo".
		// This is important so "Image" will map to built-in Image object, instead of enyo.Image control.
		return enyo._kindCtors[inKind] = enyo.Theme[inKind] || enyo[inKind] || enyo.getPath.call(enyo, inKind, true) || window[inKind] || enyo.getPath(inKind);
	}
	return enyo.defaultCtor;
};

//
// namespace for current theme ("enyo.Theme.Button" references the Button specialization for the current theme)
//
enyo.Theme = {};

enyo.registerTheme = function(inNamespace) {
	enyo.mixin(enyo.Theme, inNamespace);
};
<commit_msg>update docs, issue warning on non-unique kind name, fix naming test in enyo.kind<commit_after>
//*@protected
/**
	Default properties of enyo kinds to concatenate as opposed to
	overwriting. These are automatically used unless explicitly
	removed.
*/
enyo.concat = ["concat", "bindings"];

//*@protected
/**
	Is called during kind-initialization to make sure that any property
	noted to be concatenated will be (must be an array) so that those values
	will not be lost by subclasses overriding that property.
*/
enyo.handleConcatenatedProperties = function (ctor, proto) {
	var properties = enyo.merge(ctor.concat || [], proto.concat || []);
	var prop;
	var right;
	var left;
	while (properties.length) {
		prop = properties.shift();
		left = ctor[prop];
		right = proto[prop];
		if ((left instanceof Array) && (right instanceof Array)) {
			ctor[prop] = enyo.merge(left, right);
			// remove the reference to the property so it will not
			// conflict later
			delete proto[prop];
		}
	}
};

//* @public
/**
	Creates a JavaScript constructor function with a prototype defined by
	_inProps_. __All constructors must have a unique name__.

	_enyo.kind_ makes it easy to build a constructor-with-prototype (like a
	class) that has advanced features like prototype-chaining (inheritance).

	A plug-in system is included for extending the abilities of the kind
	generator, and constructors are allowed to perform custom operations when
	subclassed.

	If you make changes to _enyo.kind_, be sure to add or update the appropriate
	[unit tests](https://github.com/enyojs/enyo/tree/master/tools/test/core/tests).

	For more information, see the documentation on
	[Creating Kinds](https://github.com/enyojs/enyo/wiki/Creating-Kinds)
	in the Enyo Developer Guide.
*/
enyo.kind = function(inProps) {
	// kind-name to constructor map could be faulty now that a new kind exists, so we simply destroy the memoizations
	enyo._kindCtors = {};
	// extract 'name' property
	var name = inProps.name || "";
	delete inProps.name;
	// extract 'kind' property
	var hasKind = ("kind" in inProps);
	var kind = inProps.kind;
	delete inProps.kind;
	// establish base class reference
	var base = enyo.constructorForKind(kind);
	var isa = base && base.prototype || null;
	// if we have an explicit kind property with value undefined, we probably
	// tried to reference  a kind that is not yet in scope
	if (hasKind && kind === undefined || base === undefined) {
		var problem = kind === undefined ? 'undefined kind' : 'unknown kind (' + kind + ')';
		throw "enyo.kind: Attempt to subclass an " + problem + ". Check dependencies for [" + (name || "<unnamed>") + "].";
	}
	// make a boilerplate constructor
	var ctor = enyo.kind.makeCtor();
	// semi-reserved word 'constructor' causes problems with Prototype and IE, so we rename it here
	if (inProps.hasOwnProperty("constructor")) {
		inProps._constructor = inProps.constructor;
		delete inProps.constructor;
	}
	// create our prototype
	//ctor.prototype = isa ? enyo.delegate(isa) : {};
	enyo.setPrototype(ctor, isa ? enyo.delegate(isa) : {});

	// there are special cases where a base class has a property
	// that may need to be concatenated with a subclasses implementation
	// as opposed to completely overwriting it...
	enyo.handleConcatenatedProperties(ctor.prototype, inProps);

	// put in our props
	enyo.mixin(ctor.prototype, inProps);
	// alias class name as 'kind' in the prototype
	// but we actually only need to set this if a new name was used
	// not if it is inheriting from a kind anonymously
	if (name) ctor.prototype.kindName = name;
	// this is for anonymous constructors
	else ctor.prototype.kindName = base && base.prototype? base.prototype.kindName: "";
	// cache superclass constructor
	ctor.prototype.base = base;
	// reference our real constructor
	ctor.prototype.ctor = ctor;
	// support pluggable 'features'
	enyo.forEach(enyo.kind.features, function(fn){ fn(ctor, inProps); });
	// put reference into namespace
	if (name && !enyo.getPath(name)) enyo.setPath(name, ctor);
	else if (name) {
		enyo.warn("enyo.kind: " + name + " is already in use by another " +
			"kind, all kind definitions must have unique names.");
	}
	return ctor;
};

/**
	Creates a Singleton of a given kind with a given definition.
	__The name property will be the instance name of the singleton
	and must be unique__.

		enyo.singleton({
			kind: Control,
			name: "app.MySingleton",
			published: {
				value: "foo"
			},
			makeSomething: function() {
				//...
			}
		});

		app.MySingleton.makeSomething();
		app.MySingleton.setValue("bar");
*/
enyo.singleton = function(conf, context) {
	// extract 'name' property (the name of our singleton)
	var name = conf.name;
	delete(conf.name);
	// create an unnamed kind and save its constructor's function
	var kind = enyo.kind(conf);
	var inst;
	// create the singleton with the previous name and constructor
	enyo.setPath.call(context || enyo.global, name, (inst = new kind()));
	return inst;
};

//* @protected
enyo.kind.makeCtor = function() {
  return function() {;
		if (!(this instanceof arguments.callee)) {
			throw "enyo.kind: constructor called directly, not using 'new'";
		}

		// two-pass instantiation
		var result;
		var cargs = arguments;
		if (this._constructor) {
			// pure construction
			result = this._constructor.apply(this, arguments);
		}
		// defer initialization until entire constructor chain has finished
		if (this.constructed) {
			// post-constructor initialization
			this.constructed.apply(this, arguments);
		}

		for (var idx = 0; idx < enyo.kind.postConstructors.length; ++idx) {
			enyo.kind.postConstructors[idx].apply(this, cargs);
		}

		if (result) {
			return result;
		}
	};
};

// classes referenced by name can omit this namespace (e.g. "Button" instead of "enyo.Button")
enyo.kind.defaultNamespace = "enyo";

//
// feature hooks for the oop system
//
enyo.kind.features = [];

//*@protected
/**
	Post-initialize functions (after constructor has completed).
*/
enyo.kind.postConstructors = [];

//
// 'inherited' feature
//
enyo.kind.features.push(function(ctor, props) {
	var proto = ctor.prototype;
	if (!proto.inherited) {
		proto.inherited = enyo.kind.inherited;
	}
	if (proto.base) {
		// decorate function properties to support inherited (do this ex post facto so that
		// ctor.prototype is known, relies on elements in props being copied by reference)
		for (var n in props) {
			var p = props[n];
			if (enyo.isFunction(p)) {
				p._inherited = proto.base.prototype[n];
				// FIXME: we used to need some extra values for inherited, then inherited got cleaner
				// but in the meantime we used these values to support logging in Object.
				// For now we support this legacy situation, by suppling logging information here.
				p.nom = proto.kindName + '.' + n + '()';
			}
		}
	}
});

//*@protected
/**
	This method is called by enyo.Object's attempting to
	access super-methods of a parent class (kind) by calling
	_this.inherited(arguments)_ from within a kind method. This
	can only be done safely when there is known to be a super
	class with the same method.
*/
enyo.kind.inherited = function (originals, replacements) {
	// one-off methods are the fast track
	var target = originals.callee;
	var fn = target._inherited;
	// the possible exception are proxied methods being
	// executed from within a container under a different
	// context (shared methods) so we have to check one
	// level up in these cases to ensure we find the correct
	// method
	if (!fn || "function" !== typeof fn) {
		target = target.caller || {};
		fn = target._inherited;
	}
	// regardless of how we got here, just ensure we actually
	// have a function to call or else we throw a console
	// warning to notify developers they are calling a
	// super method that doesn't exist
	if ("function" === typeof fn) {
		return fn.apply(this, replacements? enyo.mixin(originals, replacements): originals);
	} else {
		enyo.warn("enyo.kind.inherited: unable to find requested " +
			"super-method from -> " + originals.callee.nom + " in " + this.kindName);
	}
};

//
// 'statics' feature
//
enyo.kind.features.push(function(ctor, props) {
	// install common statics
	enyo.mixin(ctor, enyo.kind.statics);
	// move props statics to constructor
	if (props.statics) {
		enyo.mixin(ctor, props.statics);
		delete ctor.prototype.statics;
	}
	// allow superclass customization

	var base = ctor.prototype.base;
	while (base) {
		base.subclass(ctor, props);
		base = base.prototype.base;
	}
});

enyo.kind.statics = {
	subclass: function(ctor, props) {
		//enyo.log("subclassing [" + ctor.prototype.kind + "] from [", this.prototype.kind + "]");
	},
	extend: function(props) {
		// make sure to allow concatenated properties to function
		// as expected
		enyo.handleConcatenatedProperties(this.prototype, props);
		enyo.mixin(this.prototype, props);
		// support pluggable 'features'
		var ctor = this;
		enyo.forEach(enyo.kind.features, function(fn){ fn(ctor, props); });
	}
};

//
// factory for kinds identified by strings
//
enyo._kindCtors = {};

enyo.constructorForKind = function(inKind) {
	if (inKind === null || enyo.isFunction(inKind)) {
		// in inKind is a function or explicitly null, then that's ctor, full stop.
		return inKind;
	}
	if (inKind) {
		// use memoized constructor if available...
		var ctor = enyo._kindCtors[inKind];
		if (ctor) {
			return ctor;
		}
		// otherwise look it up and memoize what we find
		//
		// if inKind is an object in enyo, say "Control", then ctor = enyo["Control"]
		// if inKind is a path under enyo, say "Heritage.Button", then ctor = enyo["Heritage.Button"] || enyo.Heritage.Button
		// if inKind is a fully qualified path, say "enyo.Heritage.Button", then ctor = enyo["enyo.Heritage.Button"] || enyo.enyo.Heritage.Button || enyo.Heritage.Button
		//
		// Note that kind "Foo" will resolve to enyo.Foo before resolving to global "Foo".
		// This is important so "Image" will map to built-in Image object, instead of enyo.Image control.
		return enyo._kindCtors[inKind] = enyo.Theme[inKind] || enyo[inKind] || enyo.getPath.call(enyo, inKind, true) || window[inKind] || enyo.getPath(inKind);
	}
	return enyo.defaultCtor;
};

//
// namespace for current theme ("enyo.Theme.Button" references the Button specialization for the current theme)
//
enyo.Theme = {};

enyo.registerTheme = function(inNamespace) {
	enyo.mixin(enyo.Theme, inNamespace);
};
<|endoftext|>


<commit_before>/*
  jQuery ui.timepickr - @VERSION
  http://code.google.com/p/jquery-utils/

  (c) Maxime Haineault <haineault@gmail.com>
  http://haineault.com

  MIT License (http://www.opensource.org/licenses/mit-license.php

  Note: if you want the original experimental plugin checkout the rev 224

  Dependencies
  ------------
  - jquery.utils.js
  - jquery.strings.js
  - ui.dropslide.js

  // Could do something interesting with this..
  U+25F4  ◴  White circle with upper left quadrant
  U+25F5  ◵  White circle with lower left quadrant
  U+25F6  ◶  White circle with lower right quadrant
  U+25F7  ◷  White circle with upper right quadrant

*/

(function($) {
    $.widget('ui.timepickr', {
        // Backward compatibility for UI < 1.6 - will be removed in 0.5.0
        // TODO: remove in 0.5
        init:  function() { this._init.apply(this, arguments); },
        _init: function() {
            var menu    = this._buildMenu();
            var element = this.element;
            element.data('timepickr.initialValue', element.val());
            menu.insertAfter(this.element);
            element
                .addClass('ui-timepickr')
                .dropslide(this.options.dropslide)
                .bind('select', this.select);

            element.blur(function(e) {
                $(this).dropslide('hide');
                $(this).val($(this).data('timepickr.initialValue'));
            });

            if (this.options.val) {
                element.val(this.options.val);
            }

            if (this.options.handle) {
                $(this.options.handle).click(function() {
                    $(element).dropslide('show');
                });
            }

            if (this.options.resetOnBlur) {
                menu.find('li > span').bind('mousedown.timepickr', function(){
                    $(element).data('timepickr.initialValue', $(element).val());
                });
            }

            if (this.options.updateLive) {
                menu.find('li').bind('mouseover.timepickr', function() {
                    $(element).timepickr('update');
                });
            }

            var hrs = menu.find('ol:eq(1)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();
            var min = menu.find('ol:eq(2)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();
            var sec = menu.find('ol:eq(3)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();

            if (this.options.convention === 24) {
                var day        = menu.find('ol:eq(0) li:eq(0)');
                var night      = menu.find('ol:eq(0) li:eq(1)');
                var dayHours   = hrs.find('li').slice(0, 12);
                var nightHours = hrs.find('li').slice(12, 24);
                var index      = 0;
                var selectHr   = function(id) {
                    hrs.find('li').removeClass('hover');
                    hrs.find('span').removeClass('ui-hover-state');
                    hrs.find('li').eq(id).addClass('hover').find('span').addClass('ui-hover-state')
                };

                day.mouseover(function() {
                    nightHours.hide();
                    dayHours.show(0);
                    index = hrs.find('li.hover').data('id') || hrs.find('li:first').data('id');
                    selectHr(index > 11 && index - 12 || index);
                    element.dropslide('redraw');
                });

                night.mouseover(function() {
                    dayHours.hide();
                    nightHours.show(0);
                    index = hrs.find('li.hover').data('id') || hrs.find('li:first').data('id');
                    selectHr(index < 12 && index + 12 || index);
                    element.dropslide('redraw');
                });
            }
            element.dropslide('redraw');
            element.data('timepickr', this);
        },

        update: function() {
            var frmt = this.options.convention === 24 && 'format24' || 'format12';
            var val = {
                h: this.getValue('hour'),
                m: this.getValue('minute'),
                s: this.getValue('second'),
                prefix: this.getValue('prefix'),
                suffix: this.getValue('suffix')
            };
            var o = $.format(this.options[frmt], val);

            $(this.element).val(o);
        },

        select: function(e) {
            var dropslide = $(this).data('dropslide');
            $(dropslide.element).timepickr('update');
            e.stopPropagation();
        },

        getHour: function() {
            return this.getValue('hour');
        },

        getMinute: function() {
            return this.getValue('minute');
        },

        getSecond: function() {
            return this.getValue('second');
        },

        getValue: function(type) {
            return $('.ui-timepickr.'+ type +'.hover', this.element.next()).text();
        },

        activate: function() {
            this.element.dropslide('activate');
        },

        destroy: function() {
            this.element.dropslide('destroy');
        },

        /* UI private methods */

        _createButton: function(i, format, className) {
            var o  = format && $.format(format, i) || i;
            var cn = className && 'ui-timepickr '+ className || 'ui-timepickr';
            return $('
').addClass(cn).data('id', i).append($('').text(o));
        },

        _createRow: function(range, format, className) {
            var row = $('
');
            var button = this._createButton;
            // Thanks to Christoph Müller-Spengler for the bug report
            $.each(range, function(idx, val){
                row.append(button(val, format || false, className || false));
            });
            return row;
        },

        _getRanges12: function() {
            var o = [], opt = this.options;
            if (opt.hours)   { o.push(this._createRow($.range(1, 13), '{0:0.2d}', 'hour')); }
            if (opt.minutes) { o.push(this._createRow(opt.rangeMin,   '{0:0.2d}', 'minute')); }
            if (opt.seconds) { o.push(this._createRow(opt.rangeSec,   '{0:0.2d}', 'second')); }
            if (opt.suffix)  { o.push(this._createRow(opt.suffix,     false,      'suffix')); }
            return o;
        },

        _getRanges24: function() {
            var o = [], opt = this.options;
            o.push(this._createRow(opt.prefix, false, 'prefix')); // prefix is required in 24h mode
            if (opt.hours)   { o.push(this._createRow($.range(0, 24),   '{0:0.2d}', 'hour')); }
            if (opt.minutes) { o.push(this._createRow(opt.rangeMin, '{0:0.2d}', 'minute')); }
            if (opt.seconds) { o.push(this._createRow(opt.rangeSec, '{0:0.2d}', 'second')); }
            return o;
        },

        _buildMenu: function() {
            var menu   = $('');
            var ranges = this.options.convention === 24
                         && this._getRanges24() || this._getRanges12();

            $.each(ranges, function(idx, val){
                menu.append(val);
            });
            return menu;
        }
    });

    $.ui.timepickr.defaults = {
        convention:  24, // 24, 12
        dropslide:   { trigger: 'focus' },
        format12:    '{h:02.d}:{m:02.d} {suffix:s}',
        format24:    '{h:02.d}:{m:02.d}',
        handle:      false,
        hours:       true,
        minutes:     true,
        seconds:     false,
        prefix:      ['am', 'pm'],
        suffix:      ['am', 'pm'],
        rangeMin:    ['00', '15', '30', '45'],
        rangeSec:    ['00', '15', '30', '45'],
        updateLive:  true,
        resetOnBlur: true,
        val:         false
    };

})(jQuery);
<commit_msg>- ui.timepickr.js: fixed IE7 bugs (missing closing tag). Special thanks to "Amit" (http://haineault.com/blog/71/#comment-688)<commit_after>/*
  jQuery ui.timepickr - @VERSION
  http://code.google.com/p/jquery-utils/

  (c) Maxime Haineault <haineault@gmail.com>
  http://haineault.com

  MIT License (http://www.opensource.org/licenses/mit-license.php

  Note: if you want the original experimental plugin checkout the rev 224

  Dependencies
  ------------
  - jquery.utils.js
  - jquery.strings.js
  - ui.dropslide.js

  // Could do something interesting with this..
  U+25F4  ◴  White circle with upper left quadrant
  U+25F5  ◵  White circle with lower left quadrant
  U+25F6  ◶  White circle with lower right quadrant
  U+25F7  ◷  White circle with upper right quadrant

*/

(function($) {
    $.widget('ui.timepickr', {
        // Backward compatibility for UI < 1.6 - will be removed in 0.5.0
        // TODO: remove in 0.5
        init:  function() { this._init.apply(this, arguments); },
        _init: function() {
            var menu    = this._buildMenu();
            var element = this.element;
            element.data('timepickr.initialValue', element.val());
            menu.insertAfter(this.element);
            element
                .addClass('ui-timepickr')
                .dropslide(this.options.dropslide)
                .bind('select', this.select);

            element.blur(function(e) {
                $(this).dropslide('hide');
                $(this).val($(this).data('timepickr.initialValue'));
            });

            if (this.options.val) {
                element.val(this.options.val);
            }

            if (this.options.handle) {
                $(this.options.handle).click(function() {
                    $(element).dropslide('show');
                });
            }

            if (this.options.resetOnBlur) {
                menu.find('li > span').bind('mousedown.timepickr', function(){
                    $(element).data('timepickr.initialValue', $(element).val());
                });
            }

            if (this.options.updateLive) {
                menu.find('li').bind('mouseover.timepickr', function() {
                    $(element).timepickr('update');
                });
            }

            var hrs = menu.find('ol:eq(1)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();
            var min = menu.find('ol:eq(2)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();
            var sec = menu.find('ol:eq(3)').find('li:first').addClass('hover').find('span').addClass('ui-hover-state').end().end();

            if (this.options.convention === 24) {
                var day        = menu.find('ol:eq(0) li:eq(0)');
                var night      = menu.find('ol:eq(0) li:eq(1)');
                var dayHours   = hrs.find('li').slice(0, 12);
                var nightHours = hrs.find('li').slice(12, 24);
                var index      = 0;
                var selectHr   = function(id) {
                    hrs.find('li').removeClass('hover');
                    hrs.find('span').removeClass('ui-hover-state');
                    hrs.find('li').eq(id).addClass('hover').find('span').addClass('ui-hover-state')
                };

                day.mouseover(function() {
                    nightHours.hide();
                    dayHours.show(0);
                    index = hrs.find('li.hover').data('id') || hrs.find('li:first').data('id');
                    selectHr(index > 11 && index - 12 || index);
                    element.dropslide('redraw');
                });

                night.mouseover(function() {
                    dayHours.hide();
                    nightHours.show(0);
                    index = hrs.find('li.hover').data('id') || hrs.find('li:first').data('id');
                    selectHr(index < 12 && index + 12 || index);
                    element.dropslide('redraw');
                });
            }
            element.dropslide('redraw');
            element.data('timepickr', this);
        },

        update: function() {
            var frmt = this.options.convention === 24 && 'format24' || 'format12';
            var val = {
                h: this.getValue('hour'),
                m: this.getValue('minute'),
                s: this.getValue('second'),
                prefix: this.getValue('prefix'),
                suffix: this.getValue('suffix')
            };
            var o = $.format(this.options[frmt], val);

            $(this.element).val(o);
        },

        select: function(e) {
            var dropslide = $(this).data('dropslide');
            $(dropslide.element).timepickr('update');
            e.stopPropagation();
        },

        getHour: function() {
            return this.getValue('hour');
        },

        getMinute: function() {
            return this.getValue('minute');
        },

        getSecond: function() {
            return this.getValue('second');
        },

        getValue: function(type) {
            return $('.ui-timepickr.'+ type +'.hover', this.element.next()).text();
        },

        activate: function() {
            this.element.dropslide('activate');
        },

        destroy: function() {
            this.element.dropslide('destroy');
        },

        /* UI private methods */

        _createButton: function(i, format, className) {
            var o  = format && $.format(format, i) || i;
            var cn = className && 'ui-timepickr '+ className || 'ui-timepickr';
            return $('
').addClass(cn).data('id', i).append($('').text(o));
        },

        _createRow: function(range, format, className) {
            var row = $('
');
            var button = this._createButton;
            // Thanks to Christoph Müller-Spengler for the bug report
            $.each(range, function(idx, val){
                row.append(button(val, format || false, className || false));
            });
            return row;
        },

        _getRanges12: function() {
            var o = [], opt = this.options;
            if (opt.hours)   { o.push(this._createRow($.range(1, 13), '{0:0.2d}', 'hour')); }
            if (opt.minutes) { o.push(this._createRow(opt.rangeMin,   '{0:0.2d}', 'minute')); }
            if (opt.seconds) { o.push(this._createRow(opt.rangeSec,   '{0:0.2d}', 'second')); }
            if (opt.suffix)  { o.push(this._createRow(opt.suffix,     false,      'suffix')); }
            return o;
        },

        _getRanges24: function() {
            var o = [], opt = this.options;
            o.push(this._createRow(opt.prefix, false, 'prefix')); // prefix is required in 24h mode
            if (opt.hours)   { o.push(this._createRow($.range(0, 24),   '{0:0.2d}', 'hour')); }
            if (opt.minutes) { o.push(this._createRow(opt.rangeMin, '{0:0.2d}', 'minute')); }
            if (opt.seconds) { o.push(this._createRow(opt.rangeSec, '{0:0.2d}', 'second')); }
            return o;
        },

        _buildMenu: function() {
            var menu   = $('');
            var ranges = this.options.convention === 24
                         && this._getRanges24() || this._getRanges12();

            $.each(ranges, function(idx, val){
                menu.append(val);
            });
            return menu;
        }
    });

    $.ui.timepickr.defaults = {
        convention:  24, // 24, 12
        dropslide:   { trigger: 'focus' },
        format12:    '{h:02.d}:{m:02.d} {suffix:s}',
        format24:    '{h:02.d}:{m:02.d}',
        handle:      false,
        hours:       true,
        minutes:     true,
        seconds:     false,
        prefix:      ['am', 'pm'],
        suffix:      ['am', 'pm'],
        rangeMin:    ['00', '15', '30', '45'],
        rangeSec:    ['00', '15', '30', '45'],
        updateLive:  true,
        resetOnBlur: true,
        val:         false
    };

})(jQuery);
<|endoftext|>


<commit_before>module.exports = function (grunt) {

	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),

		clean: {
			bootstrap: ['ui/app/static/css/bootstrap.css']
		},

		sass: {
			dev: {
				options: {
					compass: true,
					sourcemap: 'none',
					style: 'expanded'
				},
				files: {
					'../../ui/app/static/css/bootstrap.css': 'scss/bootstrap.scss'
				}
			},

			dist: {
				options: {
					compass: true,
					sourcemap: 'none',
					style: 'compressed'
				},
				files: {
					'../../ui/app/static/css/bootstrap.css': 'scss/bootstrap.scss'
				}
			},

			watch: {
				configFiles: {
					files: ['Gruntfile.js'],
					options: {
						reload: true,
						spawn: false
					}
				},

				css: {
					files: ['scss/*.scss'],
					tasks: ['clean:bootstrap', 'sass:dev'],
					options: {
						livereload: true,
						spawn: false
					}
				}
			}
		}
	});

	// Distribution
	grunt.registerTask('dist', ['sass:dist']);

	// Development
	grunt.registerTask('dev', ['clean:bootstrap', 'sass:dev']);

	// Load NPM Tasks
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-sass');
	grunt.loadNpmTasks('grunt-contrib-watch');

	// Default Task
	grunt.registerTask('default', ['watch:css']);
};<commit_msg>adjusting bug with grunt file configuration<commit_after>module.exports = function (grunt) {

	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),

		clean: {
			bootstrap: ['ui/app/static/css/bootstrap.css']
		},

		sass: {
			dev: {
				options: {
					compass: true,
					sourcemap: 'none',
					style: 'expanded'
				},
				files: {
					'../../ui/app/static/css/bootstrap.css': 'scss/bootstrap.scss'
				}
			},

			dist: {
				options: {
					compass: true,
					sourcemap: 'none',
					style: 'compressed'
				},
				files: {
					'../../ui/app/static/css/bootstrap.css': 'scss/bootstrap.scss'
				}
			}
		},

		watch: {
			configFiles: {
				files: ['Gruntfile.js'],
				options: {
					reload: true,
					spawn: false
				}
			},

			css: {
				files: ['scss/*.scss'],
				tasks: ['clean:bootstrap', 'sass:dev'],
				options: {
					livereload: true,
					spawn: false
				}
			}
		}
	});

	// Distribution
	grunt.registerTask('dist', ['sass:dist']);

	// Development
	grunt.registerTask('dev', ['clean:bootstrap', 'sass:dev']);

	// Load NPM Tasks
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-sass');
	grunt.loadNpmTasks('grunt-contrib-watch');

	// Default Task
	grunt.registerTask('default', ['watch:css']);
};<|endoftext|>


<commit_before>/**
 * Interface Building Class, will trigger the template engine and fill with data.
 */
'use strict';

import * as fsp from 'fs-promise';
import * as path from 'path';

import * as Handlebars from 'handlebars';

/**
 * Interface Builder Class
 *
 * @class InterfaceBuilder
 *
 * @property {{}|null} plugin Plugin Context, null if not running in plugin!
 * @property {string}  templatePath Template Base Path.
 *
 * @property {[]|boolean} players Player Logins, false for global (all players).
 * @property {{}|null} template Handlebars Template Instance.
 * @property {{}} data Handlebars Data.
 */
export default class {

  /**
   * Construct the Interface Builder.
   * @param {App} app App Context.
   * @param {UIFacade} facade UI Facade.
   * @param {string} viewFile View File.
   * @param {{}} [plugin] Plugin Context, optional, only when calling from plugin.
   */
  constructor (app, facade, viewFile, plugin) {
    plugin = plugin || false;

    // ManiaLink ID.
    this.id = (plugin ? plugin.name : 'core') + '__' + Math.floor((Math.random() * 10000) + 1);

    this.facade = facade;
    this.app = app;
    this.plugin = plugin;
    this.file = viewFile;

    this.template = null;

    this.globalData = {};
    this.playerData = {};

    // Add the interface to the compile stack.
    facade.stack.push(this);
  }

  /**
   * Compile the template view file.
   *
   * @returns {Promise}
   */
  compile () {
    return fsp.readFile(this.file, 'utf-8').then((source) => {
      this.template = Handlebars.compile (source);
    });
  }

  /**
   * Set Data for the template.
   * @param {{}} data
   *
   * @returns {InterfaceBuilder}
   */
  global (data) {
    this.globalData = data;
    return this;
  }

  /**
   * Set Data for the template, for a specific player.
   * @param {string} login Player Login.
   * @param {{}} data Data. Indexed by Player Logins.
   *
   * @returns {InterfaceBuilder}
   */
  player (login, data) {
    this.playerData[login] = data;
    return this;
  }

  /**
   * Update Interface. Will send update to the client(s).
   */
  update () {
    this.facade.manager.update(this);
  }

}
<commit_msg>Fixing id generation of manialinks<commit_after>/**
 * Interface Building Class, will trigger the template engine and fill with data.
 */
'use strict';

import * as fsp from 'fs-promise';
import * as path from 'path';

import * as Handlebars from 'handlebars';

/**
 * Interface Builder Class
 *
 * @class InterfaceBuilder
 *
 * @property {{}|null} plugin Plugin Context, null if not running in plugin!
 * @property {string}  templatePath Template Base Path.
 *
 * @property {[]|boolean} players Player Logins, false for global (all players).
 * @property {{}|null} template Handlebars Template Instance.
 * @property {{}} data Handlebars Data.
 */
export default class {

  /**
   * Construct the Interface Builder.
   * @param {App} app App Context.
   * @param {UIFacade} facade UI Facade.
   * @param {string} viewFile View File.
   * @param {{}} [plugin] Plugin Context, optional, only when calling from plugin.
   */
  constructor (app, facade, viewFile, plugin) {
    plugin = plugin || false;

    // ManiaLink ID.
    this.id = (plugin ? plugin.name : 'core') + '__' + viewFile;

    this.facade = facade;
    this.app = app;
    this.plugin = plugin;
    this.file = viewFile;

    this.template = null;

    this.globalData = {};
    this.playerData = {};

    // Add the interface to the compile stack.
    facade.stack.push(this);
  }

  /**
   * Compile the template view file.
   *
   * @returns {Promise}
   */
  compile () {
    return fsp.readFile(this.file, 'utf-8').then((source) => {
      this.template = Handlebars.compile (source);
    });
  }

  /**
   * Set Data for the template.
   * @param {{}} data
   *
   * @returns {InterfaceBuilder}
   */
  global (data) {
    this.globalData = data;
    return this;
  }

  /**
   * Set Data for the template, for a specific player.
   * @param {string} login Player Login.
   * @param {{}} data Data. Indexed by Player Logins.
   *
   * @returns {InterfaceBuilder}
   */
  player (login, data) {
    this.playerData[login] = data;
    return this;
  }

  /**
   * Update Interface. Will send update to the client(s).
   */
  update () {
    this.facade.manager.update(this);
  }

}
<|endoftext|>


<commit_before>export default class Collection {
    constructor(title = '', description = '', uri ='/', from, to) {
	this.title = title
	this.description = description
	this.uri = uri
	this.from = from || 1700
	this.to = to || new Date().getFullYear()
    }
}

export class IEDCollection extends Collection {
    constructor() {
	super();

	this.types = [
	    "Diaries and Journals",
	    "Family Papers",
	    "Folklore, Song, Music",
	    "Hansard",
	    "Letters (Emigrants)",
	    "Letters (Other)",
	    "Births, Deaths, Marriages",
	    "Newspapers Extracts",
	    "Shipping Advertisements",
	    "Shipping News",
	    "Official Documents",
	    "Periodical Extracts",
	    "Statistics",
	    "Wills",
	    "Interviews"
	]
    }
}

export class EPPICollection extends Collection {
    constructor() {
	super();

	this.types = ["Account", "Bill", "Report", "Command Paper"]
    }
}

export class VMRCollection extends Collection {
    constructor() {
	super();

	this.types = ["Interviews"]

	// Demographics
	this.gender = "";
	this.age = "";
	this.denomination = "";

	// Places
	this.birthplace = "";
	this.childhoodResidence = "";
	this.currentResidence = "";
	this.destination = "";
    }
}

<commit_msg>Correct bad autoindentation.<commit_after>export default class Collection {
  constructor(title = '', description = '', uri ='/', from, to) {
    this.title = title
    this.description = description
    this.uri = uri
    this.from = from || 1700
    this.to = to || new Date().getFullYear()
  }
}

export class IEDCollection extends Collection {
  constructor() {
    super()

    this.types = [
      "Diaries and Journals",
      "Family Papers",
      "Folklore, Song, Music",
      "Hansard",
      "Letters (Emigrants)",
      "Letters (Other)",
      "Births, Deaths, Marriages",
      "Newspapers Extracts",
      "Shipping Advertisements",
      "Shipping News",
      "Official Documents",
      "Periodical Extracts",
      "Statistics",
      "Wills"
    ]
  }
}

export class EPPICollection extends Collection {
  constructor() {
    super()

    this.types = ["Account", "Bill", "Report", "Command Paper"]
  }
}

export class VMRCollection extends Collection {
  constructor() {
    super()

    this.types = ["Interviews"]

    // Demographics
    this.gender = "";
    this.age = "";
    this.denomination = "";

    // Places
    this.birthplace = "";
    this.childhoodResidence = "";
    this.currentResidence = "";
    this.destination = "";
  }
}<|endoftext|>


<commit_before>import { getChallengeGem, isPassingGem } from '../reducers/helpers/gems-helper';

export default class AuthoringUtils {

  /**
   * Returns an object representing the current level, mission and challenge the user is on,
   * by returning the first unstarted challenge of the next started or unstarted mission
   * after the last mission the user has any gems for. If all challenges are complete,
   * returns the last challenge instead.
   */
  static getCurrentChallengeFromGems(authoring, gems) {
    let levels = authoring.application.levels,
        startLevel = 0,
        endLevel = levels.length - 1;

    let nextUnstartedChallenge;

    // Go backwards through the challenges to find the last mission the user has gems
    for (let i = endLevel, ii = startLevel; i >= ii; i--) {
      let level = levels[i];
      for (let j = level.missions.length - 1; j >= 0; j--) {
        let mission = level.missions[j];
        let gemInMission = false;
        let lowestMissingGem;
        for (let k = mission.challenges.length - 1; k >= 0; k--) {
          if (isPassingGem(getChallengeGem(i, j, k, gems))) {
            gemInMission = true;
          } else {
            if (gemInMission) {
              // if we've already found a gem in this mission, lowestMissingGem will be
              // the lowest challenge in this mission without a gem
              lowestMissingGem = k;
            } else {
              // if we haven't found a gem yet, this will always be the last seen challenge
              nextUnstartedChallenge = {
                level: i,
                mission: j,
                challenge: k
              };
            }
          }
        }
        if (gemInMission) {
          if (lowestMissingGem !== undefined) {
            return {
              level: i,
              mission: j,
              challenge: lowestMissingGem
            };
          } else {
            // this may be the next challenge in the same mission, or the first
            // challenge of the next mission
            return nextUnstartedChallenge;
          }
        }
      }
    }

    // No challenges have been completed
    return {
      level: 0,
      mission: 0,
      challenge: 0
    };
  }

  /**
   * Returns true if any challenge in the given mission has been attempted.
   */
  static isMissionStarted(gems, level, mission) {
    let missionGems = gems[level] && gems[level][mission],
        started = false;
    if (missionGems) {
      for (let i = 0; i < missionGems.length; i++) {
        // we just care if there are any attempts, even failing ones
        if (missionGems[i] && missionGems[i].length > 0) {
          started = true;
        }
      }
    }
    return started;
  }

  /**
   * Returns true if the given mission is beyond the current mission, and is therefore inaccesible.
   *
   * FIXME: Unlocking all missions was requested as a TEMPORARY feature, to remove gating
   * entirely for the Fall 2017 teachers until we add a feature to put this under teacher
   * control. The smallest temporary way to do this, and make it easy to revert, is to simply
   * return `false` here.
   */
  static isMissionLocked(gems, authoring, level, mission) {
    // let currChallengeRoute = this.getCurrentChallengeFromGems(authoring, gems);

    // return level > currChallengeRoute.level
    //     || (level === currChallengeRoute.level && mission > currChallengeRoute.mission);
    return false;
  }

}
<commit_msg>Fix progress utils if user has all the gems<commit_after>import { getChallengeGem, isPassingGem } from '../reducers/helpers/gems-helper';

export default class AuthoringUtils {

  /**
   * Returns an object representing the current level, mission and challenge the user is on,
   * by returning the first unstarted challenge of the next started or unstarted mission
   * after the last mission the user has any gems for. If all challenges are complete,
   * returns the last challenge instead.
   */
  static getCurrentChallengeFromGems(authoring, gems) {
    let levels = authoring.application.levels,
        startLevel = 0,
        endLevel = levels.length - 1;

    let nextUnstartedChallenge;

    // Go backwards through the challenges to find the last mission the user has gems
    for (let i = endLevel, ii = startLevel; i >= ii; i--) {
      let level = levels[i];
      for (let j = level.missions.length - 1; j >= 0; j--) {
        let mission = level.missions[j];
        let gemInMission = false;
        let lowestMissingGem;
        for (let k = mission.challenges.length - 1; k >= 0; k--) {
          if (isPassingGem(getChallengeGem(i, j, k, gems))) {
            gemInMission = true;
          } else {
            if (gemInMission) {
              // if we've already found a gem in this mission, lowestMissingGem will be
              // the lowest challenge in this mission without a gem
              lowestMissingGem = k;
            } else {
              // if we haven't found a gem yet, this will always be the last seen challenge
              nextUnstartedChallenge = {
                level: i,
                mission: j,
                challenge: k
              };
            }
          }
        }
        if (gemInMission) {
          if (lowestMissingGem !== undefined) {
            return {
              level: i,
              mission: j,
              challenge: lowestMissingGem
            };
          } else if (nextUnstartedChallenge) {  // this is only null if user has completed all
            // this may be the next challenge in the same mission, or the first
            // challenge of the next mission
            return nextUnstartedChallenge;
          }
        }
      }
    }

    // No challenges or all challenges have been completed
    return {
      level: 0,
      mission: 0,
      challenge: 0
    };
  }

  /**
   * Returns true if any challenge in the given mission has been attempted.
   */
  static isMissionStarted(gems, level, mission) {
    let missionGems = gems[level] && gems[level][mission],
        started = false;
    if (missionGems) {
      for (let i = 0; i < missionGems.length; i++) {
        // we just care if there are any attempts, even failing ones
        if (missionGems[i] && missionGems[i].length > 0) {
          started = true;
        }
      }
    }
    return started;
  }

  /**
   * Returns true if the given mission is beyond the current mission, and is therefore inaccesible.
   *
   * FIXME: Unlocking all missions was requested as a TEMPORARY feature, to remove gating
   * entirely for the Fall 2017 teachers until we add a feature to put this under teacher
   * control. The smallest temporary way to do this, and make it easy to revert, is to simply
   * return `false` here.
   */
  static isMissionLocked(gems, authoring, level, mission) {
    // let currChallengeRoute = this.getCurrentChallengeFromGems(authoring, gems);

    // return level > currChallengeRoute.level
    //     || (level === currChallengeRoute.level && mission > currChallengeRoute.mission);
    return false;
  }

}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  name: 'Something',

  requires: [
    'foam.util.Timer'
  ],

  properties: [
    {
      name: 'value',
      value: 'aaaa'
    },
    {
      name: 'timer',
      factory: function() {
        return this.Timer.create();
      }
    }
  ],

  methods: [
    function init() {
      this.timer.start();
      this.timer.propertyChange.sub('second', this.onTimer);
    }
  ],

  listeners: [
    function onTimer() {
      this.value = this.value === 'aaaa' ? 'bbbb' : 'aaaa';
    }
  ]
});

var timer = foam.util.Timer.create();
timer.start();

var E = foam.__context__.E.bind(foam.__context__);

E('b').add(
  'bold',
  E('br'),
  'HTML Injection Attempt',
  E('br')
);

E().
  add('Entities: ').
  add('foo').
  nbsp().
  entity('amp').
  add(' bar ').
  entity('lt').
  entity('quot').
  entity("#039").
  tag('br').
  write();

E('b').add(
  'color: ',
  E('font').attrs({color: 'red'}).add('red', E('br'))).write();

var e = E('font').add('click me', E('br'));
console.log('id: ', e.id);
e.write();
e.attrs({color: 'orange'}).
  style({
    fontWeight: 'bold',
    fontSize:  '24pt'
  }).
  on('click', function() { console.log('clicked'); });

var e13 = E('div').add(
  'dynamic function: ',
  foam.core.ExpressionSlot.create({
    args: [ timer.second$ ],
    code: function(s) {
      return s % 2 ?
        E('span').add('PI', 'NG').style({color: 'aqua'}) :
        E('span').add('PONG').style({color: 'orange'});
    }
  }),
  E('br'),
  timer.second$.map(function(s) {
    return s % 2 ?
      E('span').add('PI', 'NG').style({color: 'aqua'}) :
      E('span').add('PONG').style({color: 'orange'})   ;
  }),
  E('br'),
  'dynamic value: ', timer.i$,
  E('br'));
e13.write();

var e2 = E('font').add('on click (before)', E('br')).on('click', function() { console.log('clicked, before'); });
e2.write();

var e2b = E('font').add('on click (after)');
e2b.write();
e2b.on('click', function() { console.log('clicked, after'); });

E('br').write();

var e3 = E('div').add('first line, added before');
e3.write();
e3.add(E('br'),'second line, added after', E('br'));

E('div').add('add style before').style({color: 'blue'}).write();

var e5 = E('div').add('add style after');
e5.write();
e5.style({color: 'blue'});

E('br').write();

E('div').add('add class before').cssClass('important').write();

var e7 = E('div').add('add class after');
e7.write();
e7.cssClass('important');

E('font').add(E('br'), 'set attr before').attrs({color: 'blue'}).write();

var e11 = E('font').add(E('br'), 'set attr after', E('br'));
e11.write();
e11.attrs({color: 'blue'});

 var e = E('div').add(
   E('span').add("hello "),
   E('span').add("!")).write();
 e.insertBefore(E('span').add('world'), e.children[1]);

var e = E('div').add(
  E('span').add("hello "),
  E('span').add("!"));
e.insertBefore(E('span').add('world'), e.children[1]);
e.write();

var e = E('div').add(
  E('span').add("hello "),
  E('span').add("!")).write();
e.insertAfter(E('span').add('world'), e.children[0]);

var e = E('div').add(
  E('span').add("hello "),
  E('span').add("!"));
e.insertAfter(E('span').add('world'), e.children[0]);
e.write();

var e = E('div').add(
  E('span').add("hello "),
  E('span').add("!"));
e.addBefore(e.children[1], E('span').add('there '), E('span').add('world'));
e.write();

var oldChild = E().add('First Child').style({color: 'red'});
var newChild = E().add('Second Child').style({color: 'green'});
var e = E('div').tag('br').add(oldChild).tag('br').write();
e.replaceChild(newChild, oldChild);

foam.CLASS({
  name: 'RedElement',
  extends: 'foam.u2.Element',
  methods: [ function init() { this.SUPER(); this.style({color: 'red'}); } ]
});

RedElement.create().add('red element').write();

var i = E('image').attrs({
  displayWidth: 200,
  displayHeight: 200,
  data: 'Dragon.png'
});

i.write();

foam.CLASS({
  name: 'Person',
  properties: [ 'firstName', 'lastName', 'age' ],
  actions: [
    function sayHello() {
      console.log('hello');
    },
    function sayGoodbye() {
      console.log('goodbye');
    }
  ]
});

var p = Person.create({firstName: 'John', lastName: 'Doe', age: 42});

var Y =  foam.__context__.createSubContext({data: p});
console.log('data: ', Y.data);

var s = p.firstName$;
var input = foam.u2.tag.Input.create({data: 'william'});
var input2 = foam.u2.tag.Input.create({data: 'john'});
input.data$ = input2.data$;
input.write();
input2.write();

Person.FIRST_NAME.toE(Y).write();
Person.FIRST_NAME.toE(Y).write();

var e = Y.E('div').add('simple: ').add(Person.FIRST_NAME, Person.LAST_NAME);
e.write();

var e2 = Y.E('div').add('simple2: ').add(Person.getAxiomsByClass(foam.core.Property));
e2.write();

foam.u2.DetailView.create({
  data: p
}).write();

var dv2 = foam.u2.DetailView.create({
  data: p,
  showActions: true
}).write();

foam.u2.DetailView.create({
  data: foam.util.Timer.create(),
  showActions: true
}).write();

foam.u2.DetailView.create({
  data: foam.util.Timer.create(),
  showActions: true,
  properties: [ foam.util.Timer.INTERVAL, foam.util.Timer.I ],
  actions: [ foam.util.Timer.STOP, foam.util.Timer.START ]
}).write();

foam.CLASS({
  name: 'CustomDetailView',
  extends: 'foam.u2.Element',

  exports: [ 'as data' ],

  axioms: [
    foam.u2.CSS.create({
      code: function() {/*
        important { color: red; }
      */}
    })
  ],

  properties: [
    { class: 'Int', name: 'i' },
    'field1',
    'field2',
    'flip'
  ],

  actions: [
    function reset() { this.field1 = this.field2 = ''; },
    function sayHello() { console.log('hello'); }
  ],

  listeners: [
    {
      name: 'flop',
      isMerged: true,
      mergeDelay: 1000,
      code: function() {
        this.i++;
        this.flip = ! this.flip;
        this.flop();
      }
    }
  ],

  methods: [
    function initE() {
      this.flop();

      this.field1 = 'foo';
      this.field2 = 'bar';

      var o2 = this.cls_.create({field2: 'baz'});

      this.
        cssClass(this.slot(function(flip) {
            return flip ? 'important' : '';
          })).
          tag('br').
          tag('hr').
          add(
              'start: ',
              this.field1$, ' ',
              this.field2$, ' ',
              this.field1$, ' ',
              this.field2$, ' O2: ',
              o2.field2$,
              this.E('br'),
              this.FIELD1, ' ',
              this.FIELD2, ' ',
              this.E('br'),
              this.SAY_HELLO, ' ',
              this.RESET,
              this.E('br'),
              'OnKey: '
          ).
          /*
          start('notimage').
            attrs({
              data: 'dragon.png',
              displayWidth: this.slot(function(i) { return i * 10 % 100; })
            }).
          end().
          */
          start(this.FIELD1).attrs({onKey: true}).end().
          start(this.FIELD2).attrs({onKey: true}).end().
          tag('br').
          start(this.FIELD2).attrs({data$: o2.field2$}).end();
    }
  ]
}).create().write();
<commit_msg>Added more dynamic content examples to U2 Demo.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  name: 'Something',

  requires: [
    'foam.util.Timer'
  ],

  properties: [
    {
      name: 'value',
      value: 'aaaa'
    },
    {
      name: 'timer',
      factory: function() {
        return this.Timer.create();
      }
    }
  ],

  methods: [
    function init() {
      this.timer.start();
      this.timer.propertyChange.sub('second', this.onTimer);
    }
  ],

  listeners: [
    function onTimer() {
      this.value = this.value === 'aaaa' ? 'bbbb' : 'aaaa';
    }
  ]
});

var timer = foam.util.Timer.create();
timer.start();

var E = foam.__context__.E.bind(foam.__context__);

E('b').add(
  'bold',
  E('br'),
  'HTML Injection Attempt',
  E('br')
);

E().
  add('Entities: ').
  add('foo').
  nbsp().
  entity('amp').
  add(' bar ').
  entity('lt').
  entity('quot').
  entity("#039").
  tag('br').
  write();

E('b').add(
  'color: ',
  E('font').attrs({color: 'red'}).add('red', E('br'))).write();

var e = E('font').add('click me', E('br'));
console.log('id: ', e.id);
e.write();
e.attrs({color: 'orange'}).
  style({
    fontWeight: 'bold',
    fontSize:  '24pt'
  }).
  on('click', function() { console.log('clicked'); });

var e13 = E('div').add(
  'dynamic function: ',
  foam.core.ExpressionSlot.create({
    args: [ timer.second$ ],
    code: function(s) {
      return s % 2 ?
        E('span').add('PI', 'NG').style({color: 'aqua'}) :
        E('span').add('PONG').style({color: 'orange'});
    }
  }),
  ' dynamic function2: ',
  timer.second$.map(function(s) {
    return s % 2 ?
      E('span').add('PI', 'NG').style({color: 'aqua'}) :
      E('span').add('PONG').style({color: 'orange'});
  }),
  ' dynamic function3: ',
  timer.slot(function (second) {
    return second % 2 ?
      E('span').add('PI', 'NG').style({color: 'aqua'}) :
      E('span').add('PONG').style({color: 'orange'});
  }),
  ' dynamic function4: ',
  foam.core.ExpressionSlot.create({
    args: [ timer.second$ ],
    code: function(s) {
      return s % 2 ?
        E('span').add('PI', 'NG').style({color: 'aqua'}) :
        E('span').add('PONG').style({color: 'orange'});
    }
  }),
  E('br'),
  'dynamic value: ', timer.i$,
  E('br'));
e13.write();

var e2 = E('font').add('on click (before)', E('br')).on('click', function() { console.log('clicked, before'); });
e2.write();

var e2b = E('font').add('on click (after)');
e2b.write();
e2b.on('click', function() { console.log('clicked, after'); });

E('br').write();

var e3 = E('div').add('first line, added before');
e3.write();
e3.add(E('br'),'second line, added after', E('br'));

E('div').add('add style before').style({color: 'blue'}).write();

var e5 = E('div').add('add style after');
e5.write();
e5.style({color: 'blue'});

E('br').write();

E('div').add('add class before').cssClass('important').write();

var e7 = E('div').add('add class after');
e7.write();
e7.cssClass('important');

E('font').add(E('br'), 'set attr before').attrs({color: 'blue'}).write();

var e11 = E('font').add(E('br'), 'set attr after', E('br'));
e11.write();
e11.attrs({color: 'blue'});

 var e = E('div').add(
   E('span').add("hello "),
   E('span').add("!")).write();
 e.insertBefore(E('span').add('world'), e.children[1]);

var e = E('div').add(
  E('span').add("hello "),
  E('span').add("!"));
e.insertBefore(E('span').add('world'), e.children[1]);
e.write();

var e = E('div').add(
  E('span').add("hello "),
  E('span').add("!")).write();
e.insertAfter(E('span').add('world'), e.children[0]);

var e = E('div').add(
  E('span').add("hello "),
  E('span').add("!"));
e.insertAfter(E('span').add('world'), e.children[0]);
e.write();

var e = E('div').add(
  E('span').add("hello "),
  E('span').add("!"));
e.addBefore(e.children[1], E('span').add('there '), E('span').add('world'));
e.write();

var oldChild = E().add('First Child').style({color: 'red'});
var newChild = E().add('Second Child').style({color: 'green'});
var e = E('div').tag('br').add(oldChild).tag('br').write();
e.replaceChild(newChild, oldChild);

foam.CLASS({
  name: 'RedElement',
  extends: 'foam.u2.Element',
  methods: [ function init() { this.SUPER(); this.style({color: 'red'}); } ]
});

RedElement.create().add('red element').write();

var i = E('image').attrs({
  displayWidth: 200,
  displayHeight: 200,
  data: 'Dragon.png'
});

i.write();

foam.CLASS({
  name: 'Person',
  properties: [ 'firstName', 'lastName', 'age' ],
  actions: [
    function sayHello() {
      console.log('hello');
    },
    function sayGoodbye() {
      console.log('goodbye');
    }
  ]
});

var p = Person.create({firstName: 'John', lastName: 'Doe', age: 42});

var Y =  foam.__context__.createSubContext({data: p});
console.log('data: ', Y.data);

var s = p.firstName$;
var input = foam.u2.tag.Input.create({data: 'william'});
var input2 = foam.u2.tag.Input.create({data: 'john'});
input.data$ = input2.data$;
input.write();
input2.write();

Person.FIRST_NAME.toE(Y).write();
Person.FIRST_NAME.toE(Y).write();

var e = Y.E('div').add('simple: ').add(Person.FIRST_NAME, Person.LAST_NAME);
e.write();

var e2 = Y.E('div').add('simple2: ').add(Person.getAxiomsByClass(foam.core.Property));
e2.write();

foam.u2.DetailView.create({
  data: p
}).write();

var dv2 = foam.u2.DetailView.create({
  data: p,
  showActions: true
}).write();

foam.u2.DetailView.create({
  data: foam.util.Timer.create(),
  showActions: true
}).write();

foam.u2.DetailView.create({
  data: foam.util.Timer.create(),
  showActions: true,
  properties: [ foam.util.Timer.INTERVAL, foam.util.Timer.I ],
  actions: [ foam.util.Timer.STOP, foam.util.Timer.START ]
}).write();

foam.CLASS({
  name: 'CustomDetailView',
  extends: 'foam.u2.Element',

  exports: [ 'as data' ],

  axioms: [
    foam.u2.CSS.create({
      code: function() {/*
        important { color: red; }
      */}
    })
  ],

  properties: [
    { class: 'Int', name: 'i' },
    'field1',
    'field2',
    'flip'
  ],

  actions: [
    function reset() { this.field1 = this.field2 = ''; },
    function sayHello() { console.log('hello'); }
  ],

  listeners: [
    {
      name: 'flop',
      isMerged: true,
      mergeDelay: 1000,
      code: function() {
        this.i++;
        this.flip = ! this.flip;
        this.flop();
      }
    }
  ],

  methods: [
    function initE() {
      this.flop();

      this.field1 = 'foo';
      this.field2 = 'bar';

      var o2 = this.cls_.create({field2: 'baz'});

      this.
        cssClass(this.slot(function(flip) {
            return flip ? 'important' : '';
          })).
          tag('br').
          tag('hr').
          add(
              'start: ',
              this.field1$, ' ',
              this.field2$, ' ',
              this.field1$, ' ',
              this.field2$, ' O2: ',
              o2.field2$,
              this.E('br'),
              this.FIELD1, ' ',
              this.FIELD2, ' ',
              this.E('br'),
              this.SAY_HELLO, ' ',
              this.RESET,
              this.E('br'),
              'OnKey: '
          ).
          /*
          start('notimage').
            attrs({
              data: 'dragon.png',
              displayWidth: this.slot(function(i) { return i * 10 % 100; })
            }).
          end().
          */
          start(this.FIELD1).attrs({onKey: true}).end().
          start(this.FIELD2).attrs({onKey: true}).end().
          tag('br').
          start(this.FIELD2).attrs({data$: o2.field2$}).end();
    }
  ]
}).create().write();
<|endoftext|>


<commit_before>import { isArray } from 'underscore';

module.exports = {
  run(ed, sender, opts = {}) {
    if (!ed.Canvas.hasFocus() || ed.getModel().isEditing()) return;
    let components = opts.component || ed.getSelectedAll();
    components = isArray(components) ? [...components] : [components];

    // It's important to deselect components first otherwise,
    // with undo, the component will be set with the wrong `collection`
    ed.select(null);

    components.forEach(component => {
      if (!component || !component.get('removable')) {
        console.warn('The element is not removable', component);
        return;
      }
      if (component) {
        const coll = component.collection;
        coll && coll.remove(component);
      }
    });

    return components;
  }
};
<commit_msg>Add component:destroy event to ComponentDelete<commit_after>import { isArray } from 'underscore';

module.exports = {
  run(ed, sender, opts = {}) {
    if (ed.getModel().isEditing()) return;
    let components = opts.component || ed.getSelectedAll();
    components = isArray(components) ? [...components] : [components];

    // It's important to deselect components first otherwise,
    // with undo, the component will be set with the wrong `collection`
    ed.select(null);

    components.forEach(component => {
      if (!component || !component.get('removable')) {
        console.warn('The element is not removable', component);
        return;
      }
      if (component) {
        const coll = component.collection;
        component.trigger('component:destroy');
        coll && coll.remove(component);
      }
    });

    return components;
  }
};
<|endoftext|>


<commit_before>/*
This file handles processing of state before or after
communicating with database or server.

Note that signInOut is imported from ./User since cognito will
handle all the communications for us. signInOut handles fetching
login information from local storage.
*/

import * as actionTypes from '../../constants/ActionTypes';
import { deepCopy, getUUID } from '../../utils';
import { signInOut } from '../User';
import { initState as experimentInitState } from '../Experiment';

/*
*Note, will handle deep copy for you

Register a new experiment under a user
For experiment state:
1. assign an id
2. set owner

For user state:
1. set last edit experiment id
2. populate experiment repository

*/
function registerNewExperiment(state, forceNewId=false) {
	state.userState.experiments = deepCopy(state.userState.experiments);
	state.experimentState = Object.assign({}, state.experimentState);
	let { userState, experimentState } = state;
	// assign id
	// set owner
	if (!experimentState.experimentId || forceNewId) {
		experimentState.experimentId = getUUID();
		experimentState.owner = Object.assign({}, userState.user);
	}
	// set last edit
	// populate repository
	userState.lastEdittingId = experimentState.experimentId;
	userState.experiments.push({
		name: experimentState.experimentName,
		id: experimentState.experimentId
	});
}

/*
Save case: create account
It will process state before communicating with database

It is called when the first sign in of a verified user.
Typically happens when the account is created and gets
verified immediately. (will automatically sign in)

It will do the following
1. Update userState by fetching login data from local storage (handled by signInOut)
2. If there is any change in experiment, register this experiment under the user

*/
function signUpPush(state, action) {
	let new_state = Object.assign({}, state);
	// update user info from local storage
	new_state.userState = signInOut(new_state.userState, { signIn: true });

	// is experiment modified?
	// yes
	if (action.anyChange) {
		registerNewExperiment(new_state);
		new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);
	}

	return new_state;
}

/*
Fetch case: sign in
It will process state after communicating with database

It is called after signing in by cognito.
It serves to fetch data from database and sync
local states.

Note in User/index there is also a signInOut, which
serves to sync userState.user with local storage

action = {
	userData: fetched user data,
	experimentData: fetched experiment data
}
*/
function signInPull(state, action) {
	let new_state = Object.assign({}, state);
	let { userData, experimentData } = action;
	if (userData) {
		userData = userData.Item.fetch;
		new_state.userState = Object.assign({}, new_state.userState);
		new_state.userState.lastEdittingId = userData.lastEdittingId;
		new_state.userState.experiments = userData.experiments;
	}
	if (experimentData) {
		experimentData = experimentData.Item.fetch;
		new_state.experimentState = experimentData;
		new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);
	}

	return new_state;
}

/*
Save case: click save
It will process state before communicating with database

//xx if no change return; xx// should be handled before dispatching
If saving an old experiment:
	1. update its name in userState
else:
	1. register itself to current user

*/
function clickSavePush(state, action) {
	let new_state = Object.assign({}, state);
	let { userState, experimentState } = new_state;

	// if old experiment
	if (experimentState.experimentId) {
		new_state.userState = Object.assign({}, userState, {
			experiments: deepCopy(userState.experiments),
		});
		for (let item of new_state.userState.experiments) {
			if (item.id === experimentState.experimentId) {
				item.name = experimentState.experimentName;
			}
		}
		// if new
	} else {
		registerNewExperiment(new_state);
	}
	new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);

	return new_state;
}

/*
Update last editting experiment
Update local experiment state

*/
function pullExperiment(state, action) {
	let experimentState = action.data.Item.fetch;
	let new_state = Object.assign({}, state, {
		userState: Object.assign({}, state.userState, {
			lastEdittingId: experimentState.experimentId
		}),
		experimentState: experimentState
	})

	new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);

	return new_state;
}

/*
action = {
	id: experimentId
}

*/
function deleteExperiment(state, action) {
	let new_state = Object.assign({}, state, {
		userState: Object.assign({}, state.userState, {
			lastEdittingId: (state.userState.lastEdittingId === action.id) ? null : state.userState.lastEdittingId,
			experiments: state.userState.experiments.filter((item) => (item.id !== action.id)),
			lastEdittingExperimentState: (state.userState.lastEdittingId === action.id) ? null : state.userState.lastEdittingExperimentState,
		}),
		experimentState: (state.experimentState.experimentId === action.id) ? experimentInitState : state.experimentState
	});

	return new_state;
}

/*
action = {
	experimentItem: {
		id: experimentId,
		name: eperimentName
	}
}

*/
function duplicateExperiment(state, action) {
	let new_state = Object.assign({}, state, {
		userState: Object.assign({}, state.userState, {
			experiments: state.userState.experiments.slice()
		})
	});

	new_state.userState.experiments.push(action.experimentItem);
	return new_state;
}

function newExperiment(state, action) {
	let new_state = Object.assign({}, state, {
		experimentState: experimentInitState
	});

	registerNewExperiment(new_state);
	new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);

	return new_state;
}

function saveAs(state, action) {
	let new_state = Object.assign({}, state, {
		experimentState: Object.assign({}, state.experimentState, {
			experimentName: action.newName
		})
	});

	// registerNewExperiment(new_state, true);
	new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);

	return new_state;
}

export default function backendReducer(state, action) {
	switch(action.type) {
		case actionTypes.SIGN_UP_PUSH:
			return signUpPush(state, action);
		case actionTypes.SIGN_IN_PULL:
			return signInPull(state, action);
		case actionTypes.CLICK_SAVE_PUSH:
			return clickSavePush(state, action);
		case actionTypes.PULL_EXPERIMENT:
			return pullExperiment(state, action);
		case actionTypes.DELETE_EXPERIMENT:
			return deleteExperiment(state, action);
		case actionTypes.DUPLICATE_EXPERIMENT:
			return duplicateExperiment(state, action);
		case actionTypes.NEW_EXPERIMENT:
			return newExperiment(state, action);
		case actionTypes.SAVE_AS_PUSH:
			return saveAs(state, action);
		default:
			return state;
	}
}

<commit_msg>Fix new experiment bug<commit_after>/*
This file handles processing of state before or after
communicating with database or server.

Note that signInOut is imported from ./User since cognito will
handle all the communications for us. signInOut handles fetching
login information from local storage.
*/

import * as actionTypes from '../../constants/ActionTypes';
import { deepCopy, getUUID } from '../../utils';
import { signInOut } from '../User';
import { initState as experimentInitState } from '../Experiment';

/*
*Note, will handle deep copy for you

Register a new experiment under a user
For experiment state:
1. assign an id
2. set owner

For user state:
1. set last edit experiment id
2. populate experiment repository

*/
function registerNewExperiment(state, forceNewId=false) {
	state.userState.experiments = deepCopy(state.userState.experiments);
	state.experimentState = Object.assign({}, state.experimentState);
	let { userState, experimentState } = state;
	// assign id
	// set owner
	if (!experimentState.experimentId || forceNewId) {
		experimentState.experimentId = getUUID();
		experimentState.owner = Object.assign({}, userState.user);
	}
	// set last edit
	// populate repository
	userState.lastEdittingId = experimentState.experimentId;
	userState.experiments.push({
		name: experimentState.experimentName,
		id: experimentState.experimentId
	});
}

/*
Save case: create account
It will process state before communicating with database

It is called when the first sign in of a verified user.
Typically happens when the account is created and gets
verified immediately. (will automatically sign in)

It will do the following
1. Update userState by fetching login data from local storage (handled by signInOut)
2. If there is any change in experiment, register this experiment under the user

*/
function signUpPush(state, action) {
	let new_state = Object.assign({}, state);
	// update user info from local storage
	new_state.userState = signInOut(new_state.userState, { signIn: true });

	// is experiment modified?
	// yes
	if (action.anyChange) {
		registerNewExperiment(new_state);
		new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);
	}

	return new_state;
}

/*
Fetch case: sign in
It will process state after communicating with database

It is called after signing in by cognito.
It serves to fetch data from database and sync
local states.

Note in User/index there is also a signInOut, which
serves to sync userState.user with local storage

action = {
	userData: fetched user data,
	experimentData: fetched experiment data
}
*/
function signInPull(state, action) {
	let new_state = Object.assign({}, state);
	let { userData, experimentData } = action;
	if (userData) {
		userData = userData.Item.fetch;
		new_state.userState = Object.assign({}, new_state.userState);
		new_state.userState.lastEdittingId = userData.lastEdittingId;
		new_state.userState.experiments = userData.experiments;
	}
	if (experimentData) {
		experimentData = experimentData.Item.fetch;
		new_state.experimentState = experimentData;
		new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);
	}

	return new_state;
}

/*
Save case: click save
It will process state before communicating with database

//xx if no change return; xx// should be handled before dispatching
If saving an old experiment:
	1. update its name in userState
else:
	1. register itself to current user

*/
function clickSavePush(state, action) {
	let new_state = Object.assign({}, state);
	let { userState, experimentState } = new_state;

	// if old experiment
	if (experimentState.experimentId) {
		new_state.userState = Object.assign({}, userState, {
			experiments: deepCopy(userState.experiments),
		});
		for (let item of new_state.userState.experiments) {
			if (item.id === experimentState.experimentId) {
				item.name = experimentState.experimentName;
			}
		}
		// if new
	} else {
		registerNewExperiment(new_state);
	}
	new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);

	return new_state;
}

/*
Update last editting experiment
Update local experiment state

*/
function pullExperiment(state, action) {
	let experimentState = action.data.Item.fetch;
	let new_state = Object.assign({}, state, {
		userState: Object.assign({}, state.userState, {
			lastEdittingId: experimentState.experimentId
		}),
		experimentState: experimentState
	})

	new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);

	return new_state;
}

/*
action = {
	id: experimentId
}

*/
function deleteExperiment(state, action) {
	let new_state = Object.assign({}, state, {
		userState: Object.assign({}, state.userState, {
			lastEdittingId: (state.userState.lastEdittingId === action.id) ? null : state.userState.lastEdittingId,
			experiments: state.userState.experiments.filter((item) => (item.id !== action.id)),
			lastEdittingExperimentState: (state.userState.lastEdittingId === action.id) ? null : state.userState.lastEdittingExperimentState,
		}),
		experimentState: (state.experimentState.experimentId === action.id) ? experimentInitState : state.experimentState
	});

	return new_state;
}

/*
action = {
	experimentItem: {
		id: experimentId,
		name: eperimentName
	}
}

*/
function duplicateExperiment(state, action) {
	let new_state = Object.assign({}, state, {
		userState: Object.assign({}, state.userState, {
			experiments: state.userState.experiments.slice()
		})
	});

	new_state.userState.experiments.push(action.experimentItem);
	return new_state;
}

function newExperiment(state, action) {
	let new_state = Object.assign({}, state, {
		experimentState: experimentInitState
	});

	// registerNewExperiment(new_state);
	new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);

	return new_state;
}

function saveAs(state, action) {
	let new_state = Object.assign({}, state, {
		experimentState: Object.assign({}, state.experimentState, {
			experimentName: action.newName
		})
	});

	registerNewExperiment(new_state, true);
	new_state.userState.lastEdittingExperimentState = deepCopy(new_state.experimentState);

	return new_state;
}

export default function backendReducer(state, action) {
	switch(action.type) {
		case actionTypes.SIGN_UP_PUSH:
			return signUpPush(state, action);
		case actionTypes.SIGN_IN_PULL:
			return signInPull(state, action);
		case actionTypes.CLICK_SAVE_PUSH:
			return clickSavePush(state, action);
		case actionTypes.PULL_EXPERIMENT:
			return pullExperiment(state, action);
		case actionTypes.DELETE_EXPERIMENT:
			return deleteExperiment(state, action);
		case actionTypes.DUPLICATE_EXPERIMENT:
			return duplicateExperiment(state, action);
		case actionTypes.NEW_EXPERIMENT:
			return newExperiment(state, action);
		case actionTypes.SAVE_AS_PUSH:
			return saveAs(state, action);
		default:
			return state;
	}
}

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015, Alexander Orzechowski.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * Currently in beta stage. Changes can and will be made to the core mechanic
 * making this not backwards compatible.
 *
 * Github: https://github.com/Need4Speed402/tessellator
 */

Tessellator.Polygon = function (vertices){
    this.vertices = vertices;
};

Tessellator.Polygon.prototype.getNormal = function (){
    var normal = Tessellator.vec3();
    var poly = this.vertices;

    for (var i = 0; i < poly.length; i += 3){
        normal[0] += (poly[i + 1] - poly[(i + 4) % poly.length]) * (poly[i + 2] + poly[(i + 5) % poly.length]);
        normal[1] += (poly[i + 2] - poly[(i + 5) % poly.length]) * (poly[i + 0] + poly[(i + 3) % poly.length]);
        normal[2] += (poly[i + 0] - poly[(i + 3) % poly.length]) * (poly[i + 1] + poly[(i + 4) % poly.length]);
    };

    return normal.normalize();
};

Tessellator.Polygon.prototype.convert2D = function (normal){
    if (!normal){
        normal = this.getNormal();
    };

    var up = normal.clone().normalize();
    var right, backward;

    if (Math.abs(normal[0]) > Math.abs(normal[2])){
        right = up.cross(Tessellator.vec3(0, 0, 1));
    }else{
        right = up.cross(Tessellator.vec3(1, 0, 0));
    };
    right.normalize();
    backward = right.clone().cross(up);

    var mat = Tessellator.mat4(
        right[0], up[0], backward[0], 0,
        right[1], up[1], backward[1], 0,
        right[2], up[2], backward[2], 0,
        0, 0, 0, 1
    );

    var poly = this.vertices;
    var dPoly = new Float32Array(poly.length / 3 * 2);

    for (var i = 0; i < poly.length / 3; i++){
        var v = Tessellator.vec4(poly[i * 3], poly[i * 3 + 1], poly[i * 3 + 2], 1);
        v.multiply(mat);

        dPoly[i * 2] = v[0];
        dPoly[i * 2 + 1] = v[1];
    };

    this.vertices = dPoly;
};

Tessellator.Polygon.prototype.convertToTriangles = function (off){
    var poly = this.vertices;
    var points = poly.length / 2;

    off = off || 0;

    if (points <= 2){
        throw "not a complete polygon";
    };

    var indices = new Tessellator.Array(16);

    var avl = new Array(points);
    for (var i = 0; i < points; i++){
        avl[i] = i;
    };

    for (var i = 0; i < 3 * avl.length || avl.length >= 6; i++){
        var i0 = avl[(i + 0) % avl.length],
            i1 = avl[(i + 1) % avl.length],
            i2 = avl[(i + 2) % avl.length],

            ax = poly[i0 * 2],  ay = poly[i0 * 2 + 1],
            bx = poly[i1 * 2],  by = poly[i1 * 2 + 1],
            cx = poly[i2 * 2],  cy = poly[i2 * 2 + 1];

        if ((ay - by) * (cx - bx) + (bx - ax) * (cy - by) >= 0){
            for (var ii = 0; ii < avl.length; (ii === i - 1) ? ii += 3 : ii++){
                var p = avl[ii],

                    v0x = cx              - ax,
                    v0y = cy              - ay,
                    v1x = bx              - ax,
                    v1y = by              - ay,
                    v2x = poly[p * 2 + 0] - ax,
                    v2y = poly[p * 2 + 1] - ay,

                    dot00 = v0x * v0x + v0y * v0y,
                    dot01 = v0x * v1x + v0y * v1y,
                    dot02 = v0x * v2x + v0y * v2y,
                    dot11 = v1x * v1x + v1y * v1y,
                    dot12 = v1x * v2x + v1y * v2y;

                var d = dot00 * dot11 - dot01 * dot01;
                var u = (dot11 * dot02 - dot01 * dot12) / d;
                var v = (dot00 * dot12 - dot01 * dot02) / d;

                if (u >= 0 && v >= 0 && u + v < 1){
                    break;
                };
            };

            indices.push(i0 + off, i1 + off, i2 + off);
            avl.splice((i + 1) % avl.length, 1);
            i = -1;
        };
    };

    indices.push(avl[0] + off, avl[1] + off, avl[2] + off);
    return indices;
};<commit_msg>got some work dopnw<commit_after>/**
 * Copyright (c) 2015, Alexander Orzechowski.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/**
 * Currently in beta stage. Changes can and will be made to the core mechanic
 * making this not backwards compatible.
 *
 * Github: https://github.com/Need4Speed402/tessellator
 */

Tessellator.Polygon = function (vertices){
    this.vertices = vertices;
};

Tessellator.Polygon.prototype.getNormal = function (){
    var normal = Tessellator.vec3();
    var poly = this.vertices;

    for (var i = 0; i < poly.length; i += 3){
        normal[0] += (poly[i + 1] - poly[(i + 4) % poly.length]) * (poly[i + 2] + poly[(i + 5) % poly.length]);
        normal[1] += (poly[i + 2] - poly[(i + 5) % poly.length]) * (poly[i + 0] + poly[(i + 3) % poly.length]);
        normal[2] += (poly[i + 0] - poly[(i + 3) % poly.length]) * (poly[i + 1] + poly[(i + 4) % poly.length]);
    };

    return normal.normalize();
};

Tessellator.Polygon.prototype.convert2D = function (normal){
    if (!normal){
        normal = this.getNormal();
    };

    var up = normal.clone().normalize();
    var right, backward;

    if (Math.abs(normal[0]) > Math.abs(normal[2])){
        right = up.cross(Tessellator.vec3(0, 0, 1));
    }else{
        right = up.cross(Tessellator.vec3(1, 0, 0));
    };
    right.normalize();
    backward = right.clone().cross(up);

    var mat = Tessellator.mat4(
        right[0], up[0], backward[0], 0,
        right[1], up[1], backward[1], 0,
        right[2], up[2], backward[2], 0,
        0, 0, 0, 1
    );

    var poly = this.vertices;
    var dPoly = new Float32Array(poly.length / 3 * 2);

    for (var i = 0; i < poly.length / 3; i++){
        var v = Tessellator.vec4(poly[i * 3], poly[i * 3 + 1], poly[i * 3 + 2], 1);
        v.multiply(mat);

        dPoly[i * 2] = v[0];
        dPoly[i * 2 + 1] = v[1];
    };

    this.vertices = dPoly;
};

Tessellator.Polygon.prototype.convertToTriangles = function (off){
    var poly = this.vertices;
    var points = poly.length / 2;

    off = off || 0;

    if (points <= 2){
        throw "not a complete polygon";
    };

    var indices = new Tessellator.Array(16);

    var avl = new Array(points);
    for (var i = 0; i < points; i++){
        avl[i] = i;
    };

    for (var i = 0; i < avl.length > 3; i++){
        var i0 = avl[(i + 0) % avl.length],
            i1 = avl[(i + 1) % avl.length],
            i2 = avl[(i + 2) % avl.length],

            ax = poly[i0 * 2],  ay = poly[i0 * 2 + 1],
            bx = poly[i1 * 2],  by = poly[i1 * 2 + 1],
            cx = poly[i2 * 2],  cy = poly[i2 * 2 + 1];

        if ((ay - by) * (cx - bx) + (bx - ax) * (cy - by) >= 0){
            for (var ii = 0; ii < avl.length; (ii === i - 1) ? ii += 3 : ii++){
                var p = avl[ii],

                    v0x = cx              - ax,
                    v0y = cy              - ay,
                    v1x = bx              - ax,
                    v1y = by              - ay,
                    v2x = poly[p * 2 + 0] - ax,
                    v2y = poly[p * 2 + 1] - ay,

                    dot00 = v0x * v0x + v0y * v0y,
                    dot01 = v0x * v1x + v0y * v1y,
                    dot02 = v0x * v2x + v0y * v2y,
                    dot11 = v1x * v1x + v1y * v1y,
                    dot12 = v1x * v2x + v1y * v2y;

                var d = dot00 * dot11 - dot01 * dot01;
                var u = (dot11 * dot02 - dot01 * dot12) / d;
                var v = (dot00 * dot12 - dot01 * dot02) / d;

                if (u >= 0 && v >= 0 && u + v < 1){
                    break;
                };
            };

            indices.push(i0 + off, i1 + off, i2 + off);
            avl.splice((i + 1) % avl.length, 1);
            i = -1;
        };
    };

    indices.push(avl[0] + off, avl[1] + off, avl[2] + off);
    return indices;
};
<|endoftext|>


<commit_before>import moment from 'moment';
import { seconds_to_duration } from './time.js';
import DOMPurify from 'dompurify';
import _ from 'lodash';

const sanitize = DOMPurify.sanitize;

export function buildTooltip(bucket, e) {
  // WARNING: XSS risk, make sure to sanitize properly
  // FIXME: Not actually tested against XSS attacks, implementation needs to be verified in tests.
  let inner = 'Unknown bucket type';
  if (bucket.type == 'currentwindow') {
    inner = `

App:	${sanitize(e.data.app)}

Title:	${sanitize(e.data.title)}

      `;
  } else if (bucket.type == 'web.tab.current') {
    inner = `

Title:	${sanitize(e.data.title)}

URL:	${sanitize(e.data.url)}

      `;
  } else if (bucket.type.startsWith('app.editor')) {
    inner = `

Filename:	${sanitize(_.last(e.data.file.split('/')))}

Path:	${sanitize(e.data.file)}

Language:	${sanitize(e.data.language)}

      `;
  } else if (bucket.type.startsWith('general.stopwatch')) {
    inner = `

Label:	${sanitize(e.data.label)}

      `;
  } else {
    inner = `

Data:	${sanitize(JSON.stringify(e.data))}

      `;
  }
  return `
${inner}

Time:	${moment(e.timestamp).format()}

Duration:	${seconds_to_duration(e.duration)}

`;
}
<commit_msg>feat: added stop time to timeline tooltip (fixes https://github.com/ActivityWatch/aw-webui/issues/200#issuecomment-674582218)<commit_after>import moment from 'moment';
import { seconds_to_duration } from './time.js';
import DOMPurify from 'dompurify';
import _ from 'lodash';

const sanitize = DOMPurify.sanitize;

export function buildTooltip(bucket, e) {
  // WARNING: XSS risk, make sure to sanitize properly
  // FIXME: Not actually tested against XSS attacks, implementation needs to be verified in tests.
  let inner = 'Unknown bucket type';
  if (bucket.type == 'currentwindow') {
    inner = `

App:	${sanitize(e.data.app)}

Title:	${sanitize(e.data.title)}

      `;
  } else if (bucket.type == 'web.tab.current') {
    inner = `

Title:	${sanitize(e.data.title)}

URL:	${sanitize(e.data.url)}

      `;
  } else if (bucket.type.startsWith('app.editor')) {
    inner = `

Filename:	${sanitize(_.last(e.data.file.split('/')))}

Path:	${sanitize(e.data.file)}

Language:	${sanitize(e.data.language)}

      `;
  } else if (bucket.type.startsWith('general.stopwatch')) {
    inner = `

Label:	${sanitize(e.data.label)}

      `;
  } else {
    inner = `

Data:	${sanitize(JSON.stringify(e.data))}

      `;
  }
  return `

Start:	${moment(e.timestamp).format()}

Stop:	${moment(e.timestamp).add(e.duration, 'seconds').format()}

Duration:	${seconds_to_duration(e.duration)}

    ${inner}

`;
}
<|endoftext|>