<commit_before>/*!
 * jQuery Mobile Events
 * by Ben Major (www.ben-major.co.uk)
 *
 * Copyright 2011, Ben Major
 * Licensed under the MIT License:
 *
 * 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.
 *
 */

(function($) {

	var settings = {
		swipe_h_threshold 	: 50,
		swipe_v_threshold 	: 50,
		taphold_threshold 	: 750,
		doubletap_int       : 500,
		touch_capable       : ('ontouchstart' in document.documentElement),
		orientation_support : ('orientation' in window && 'onorientationchange' in window),
		startevent        	: ('ontouchstart' in document.documentElement) ? 'touchstart' : 'mousedown',
		endevent		  	: ('ontouchstart' in document.documentElement) ? 'touchend' : 'mouseup',
		moveevent         	: ('ontouchstart' in document.documentElement) ? 'touchmove' : 'mousemove',
		tapevent		  	: ('ontouchstart' in document.documentElement) ? 'tap' : 'click',
		scrollevent       	: ('ontouchstart' in document.documentElement) ? 'touchmove' : 'scroll',
		hold_timer 			: null,
		tap_timer 			: null
	};

	// Add Event shortcuts:
	$.each(('tapstart tapend tap singletap doubletap taphold swipe swipeup swiperight swipedown swipeleft scrollstart scrollend orientationchange').split(' '), function(i, name) {
		$.fn[name] = function(fn)
		{
			return fn ? this.bind(name, fn) : this.trigger(name);
		};

		$.attrFn[name] = true;
	});

	// tapstart Event:
	$.event.special.tapstart = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject);

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					triggerCustomEvent(thisObject, 'tapstart', e)
				}
			});
		}
	}

	// tapend Event:
	$.event.special.tapend = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject);

			$this.bind(settings.endevent, function(e) {
				triggerCustomEvent(thisObject, 'tapend', e);
			});
		}
	}

	// taphold Event:
	$.event.special.taphold = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject),
				origTarget,
				timer,
				start_pos = { x : 0, y : 0 };

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					$this.data('tapheld', false);
					origTarget = e.target;
					start_pos.x = (settings.touch_capabale) ? e.targetTouches[0].pageX : e.pageX;
					start_pos.y = (settings.touch_capabale) ? e.targetTouches[0].pageY : e.pageY;
					settings.hold_timer = window.setTimeout(function() {
						var end_x = (settings.touch_capabale) ? e.targetTouches[0].pageX : e.pageX,
							end_y = (settings.touch_capabale) ? e.targetTouches[0].pageY : e.pageY;
						if(e.target == origTarget && (start_pos.x == end_x && start_pos.y == end_y))
						{
							$this.data('tapheld', true);
							triggerCustomEvent(thisObject, 'taphold', e);
						}
					}, settings.taphold_threshold);
				}
			}).bind(settings.endevent, function() {
				window.clearTimeout(settings.hold_timer);
			});
		}
	}

	// doubletap Event:
	$.event.special.doubletap = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject),
				origTarget,
				action;

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					$this.data('doubletapped', false);
					origTarget = e.target;
				}
			}).bind(settings.endevent, function(e) {
				var now = new Date().getTime();
				var lastTouch = $this.data('lastTouch') || now + 1;
				var delta = now - lastTouch;
				window.clearTimeout(action);

				if(delta < settings.doubletap_int && delta > 0 && (e.target == origTarget))
				{
					$this.data('doubletapped', true);
					window.clearTimeout(settings.tap_timer);
					triggerCustomEvent(thisObject, 'doubletap', e);
				}
				else
				{
					$this.data('lastTouch', now);
					action = window.setTimeout(function(e){ window.clearTimeout(action); }, settings.doubletap_int, [e]);
				}
				$this.data('lastTouch', now);
			});
		}
	}

	// singletap Event:
	// This is used in conjuction with doubletap when both events are needed on the same element
	$.event.special.singletap = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject),
				origTarget = null,
				startTime  = null;

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					startTime = new Date().getTime();
					origTarget = e.target;
				}
			}).bind(settings.endevent, function(e) {
				if(e.target == origTarget)
				{
					settings.tap_timer = window.setTimeout(function() {
						if(!$this.data('doubletapped') && !$this.data('tapheld'))
						{
							triggerCustomEvent(thisObject, 'singletap', e);
						}
					}, settings.doubletap_int);
				}
			});
		}
	}

	// tap Event:
	$.event.special.tap = {
		setup: function() {
			var thisObject = this,
				$this = $(thisObject),
			    started = false,
				origTarget = null,
				start_time,
				start_pos = { x : 0, y : 0 };

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					started = true;
					start_pos.x = (settings.touch_capabale) ? e.targetTouches[0].pageX : e.pageX;
					start_pos.y = (settings.touch_capabale) ? e.targetTouches[0].pageY : e.pageY;
					start_time = new Date().getTime();
					origTarget = e.target;
				}
			}).bind(settings.endevent, function(e) {
				// Only trigger if they've started, and the target matches:
				var end_x = (settings.touch_capabale) ? e.targetTouches[0].pageX : e.pageX,
					end_y = (settings.touch_capabale) ? e.targetTouches[0].pageY : e.pageY;

				if(origTarget == e.target && started && ((new Date().getTime() - start_time) < settings.taphold_threshold) && (start_pos.x == end_x && start_pos.y == end_y))
				{
					triggerCustomEvent(thisObject, 'tap', e);
				}
			});
		}
	};

	// swipe Event (also handles swipeup, swiperight, swipedown and swipeleft):
	$.event.special.swipe = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject),
				originalCoord = { x: 0, y: 0 },
			    finalCoord    = { x: 0, y: 0 };

			// Screen touched, store the original coordinate
			function touchStart(event)
			{
				originalCoord.x = (settings.touch_capable) ? event.targetTouches[0].pageX : event.pageX;
				originalCoord.y = (settings.touch_capable) ? event.targetTouches[0].pageY : event.pageY;
				finalCoord.x = originalCoord.x
				finalCoord.y = originalCoord.y
			}

			// Store coordinates as finger is swiping
			function touchMove(event)
			{
				event.preventDefault();
				finalCoord.x = (settings.touch_capable) ? event.targetTouches[0].pageX : event.pageX;
				finalCoord.y = (settings.touch_capable) ? event.targetTouches[0].pageY : event.pageY;
				window.clearTimeout(settings.hold_timer);
			}

			function touchEnd(e)
			{
				var swipedir;
				if(originalCoord.y > finalCoord.y && (originalCoord.y - finalCoord.y > settings.swipe_v_threshold)) { swipedir = 'swipeup'; }
				if(originalCoord.x < finalCoord.x && (finalCoord.x - originalCoord.x > settings.swipe_h_threshold)) { swipedir = 'swiperight'; }
				if(originalCoord.y < finalCoord.y && (finalCoord.y - originalCoord.y > settings.swipe_v_threshold)) { swipedir = 'swipedown'; }
				if(originalCoord.x > finalCoord.x && (originalCoord.x - finalCoord.x > settings.swipe_h_threshold)) { swipedir = 'swipeleft'; }
				if(swipedir != undefined)
				{
					$this.trigger('swipe').trigger(swipedir);
				}
			}

			// Add gestures to all swipable areas
			thisObject.addEventListener(settings.startevent, touchStart, false);
			thisObject.addEventListener(settings.moveevent, touchMove, false);
			thisObject.addEventListener(settings.endevent, touchEnd, false);
		}
	};

	// scrollstart Event (also handles scrollend):
	$.event.special.scrollstart = {
		setup: function() {
			var thisObject = this,
				$this = $(thisObject),
				scrolling,
				timer;

			function trigger(event, state)
			{
				scrolling = state;
				triggerCustomEvent(thisObject, scrolling ? 'scrollstart' : 'scrollend', event);
			}

			// iPhone triggers scroll after a small delay; use touchmove instead
			$this.bind(settings.scrollevent, function(event) {
				if(!scrolling)
				{
					trigger(event, true);
				}

				clearTimeout(timer);
				timer = setTimeout(function() { trigger(event, false); }, 50);
			});
		}
	};

	// This is the orientation change (largely borrowed from jQuery Mobile):
	var win = $(window),
		special_event,
		get_orientation,
		last_orientation,
		initial_orientation_is_landscape,
		initial_orientation_is_default,
		portrait_map = { '0': true, '180': true };

	if(settings.orientation_support)
	{
		var ww = window.innerWidth || $(window).width(),
			wh = window.innerHeight || $(window).height(),
			landscape_threshold = 50;

		initial_orientation_is_landscape = ww > wh && (ww - wh) > landscape_threshold;
		initial_orientation_is_default = portrait_map[window.orientation];

		if((initial_orientation_is_landscape && initial_orientation_is_default) || (!initial_orientation_is_landscape && !initial_orientation_is_default))
		{
			portrait_map = { '-90': true, '90': true };
		}
	}

	$.event.special.orientationchange = special_event = {
		setup: function() {
			// If the event is supported natively, return false so that jQuery
			// will bind to the event using DOM methods.
			if(settings.orientation_support)
			{
				return false;
			}

			// Get the current orientation to avoid initial double-triggering.
			last_orientation = get_orientation();

			win.bind('throttledresize', handler);
		},
		teardown: function()
		{
			if (settings.orientation_support)
			{
				return false;
			}

			win.unbind('throttledresize', handler);
		},
		add: function(handleObj)
		{
			// Save a reference to the bound event handler.
			var old_handler = handleObj.handler;

			handleObj.handler = function(event)
			{
				event.orientation = get_orientation();
				return old_handler.apply(this, arguments);
			};
		}
	};

	// If the event is not supported natively, this handler will be bound to
	// the window resize event to simulate the orientationchange event.
	function handler()
	{
		// Get the current orientation.
		var orientation = get_orientation();

		if(orientation !== last_orientation)
		{
			// The orientation has changed, so trigger the orientationchange event.
			last_orientation = orientation;
			win.trigger( "orientationchange" );
		}
	}

	$.event.special.orientationchange.orientation = get_orientation = function() {
		var isPortrait = true,
		    elem = document.documentElement;

		if(settings.orientation_support)
		{
			isPortrait = portrait_map[window.orientation];
		}
		else
		{
			isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
		}

		return isPortrait ? 'portrait' : 'landscape';
	};

	// throttle Handler:
	$.event.special.throttledresize = {
		setup: function()
		{
			$(this).bind('resize', throttle_handler);
		},
		teardown: function()
		{
			$(this).unbind('resize', throttle_handler);
		}
	};

	var throttle = 250,
		throttle_handler = function()
		{
			curr = (new Date()).getTime();
			diff = curr - lastCall;

			if(diff >= throttle)
			{
				lastCall = curr;
				$(this).trigger('throttledresize');

			}
			else
			{
				if(heldCall)
				{
					window.clearTimeout(heldCall);
				}

				// Promise a held call will still execute
				heldCall = window.setTimeout(handler, throttle - diff);
			}
		},
		lastCall = 0,
		heldCall,
		curr,
		diff;

	// Trigger a custom event:
	function triggerCustomEvent( obj, eventType, event ) {
		var originalType = event.type;
		event.type = eventType;
		$.event.handle.call( obj, event );
		event.type = originalType;
	}

	// Correctly bind anything we've overloaded:
	$.each({
		scrollend: 'scrollstart',
		swipeup: 'swipe',
		swiperight: 'swipe',
		swipedown: 'swipe',
		swipeleft: 'swipe'
	}, function(e, srcE) {
		$.event.special[e] =
		{
			setup: function() {
				$(this).bind(srcE, $.noop);
			}
		};
	});

}) (jQuery);
<commit_msg>Update src/jquery.mobile-events.js<commit_after>/*!
 * jQuery Mobile Events
 * by Ben Major (www.ben-major.co.uk)
 *
 * Copyright 2011, Ben Major
 * Licensed under the MIT License:
 *
 * 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.
 *
 */

(function($) {

	var settings = {
		swipe_h_threshold 	: 50,
		swipe_v_threshold 	: 50,
		taphold_threshold 	: 750,
		doubletap_int       : 500,
		touch_capable       : ('ontouchstart' in document.documentElement),
		orientation_support : ('orientation' in window && 'onorientationchange' in window),
		startevent        	: ('ontouchstart' in document.documentElement) ? 'touchstart' : 'mousedown',
		endevent		  	: ('ontouchstart' in document.documentElement) ? 'touchend' : 'mouseup',
		moveevent         	: ('ontouchstart' in document.documentElement) ? 'touchmove' : 'mousemove',
		tapevent		  	: ('ontouchstart' in document.documentElement) ? 'tap' : 'click',
		scrollevent       	: ('ontouchstart' in document.documentElement) ? 'touchmove' : 'scroll',
		hold_timer 			: null,
		tap_timer 			: null
	};

	// Add Event shortcuts:
	$.each(('tapstart tapend tap singletap doubletap taphold swipe swipeup swiperight swipedown swipeleft scrollstart scrollend orientationchange').split(' '), function(i, name) {
		$.fn[name] = function(fn)
		{
			return fn ? this.bind(name, fn) : this.trigger(name);
		};

		$.attrFn[name] = true;
	});

	// tapstart Event:
	$.event.special.tapstart = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject);

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					triggerCustomEvent(thisObject, 'tapstart', e)
				}
			});
		}
	}

	// tapend Event:
	$.event.special.tapend = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject);

			$this.bind(settings.endevent, function(e) {
				triggerCustomEvent(thisObject, 'tapend', e);
			});
		}
	}

	// taphold Event:
	$.event.special.taphold = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject),
				origTarget,
				timer,
				start_pos = { x : 0, y : 0 };

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					$this.data('tapheld', false);
					origTarget = e.target;
					start_pos.x = (settings.touch_capabale) ? e.targetTouches[0].pageX : e.pageX;
					start_pos.y = (settings.touch_capabale) ? e.targetTouches[0].pageY : e.pageY;
					settings.hold_timer = window.setTimeout(function() {
						var end_x = (settings.touch_capabale) ? e.targetTouches[0].pageX : e.pageX,
							end_y = (settings.touch_capabale) ? e.targetTouches[0].pageY : e.pageY;
						if(e.target == origTarget && (start_pos.x == end_x && start_pos.y == end_y))
						{
							$this.data('tapheld', true);
							triggerCustomEvent(thisObject, 'taphold', e);
						}
					}, settings.taphold_threshold);
				}
			}).bind(settings.endevent, function() {
				window.clearTimeout(settings.hold_timer);
			});
		}
	}

	// doubletap Event:
	$.event.special.doubletap = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject),
				origTarget,
				action;

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					$this.data('doubletapped', false);
					origTarget = e.target;
				}
			}).bind(settings.endevent, function(e) {
				var now = new Date().getTime();
				var lastTouch = $this.data('lastTouch') || now + 1;
				var delta = now - lastTouch;
				window.clearTimeout(action);

				if(delta < settings.doubletap_int && delta > 0 && (e.target == origTarget) && delta > 100)
				{
					$this.data('doubletapped', true);
					window.clearTimeout(settings.tap_timer);
					triggerCustomEvent(thisObject, 'doubletap', e);
				}
				else
				{
					$this.data('lastTouch', now);
					action = window.setTimeout(function(e){ window.clearTimeout(action); }, settings.doubletap_int, [e]);
				}
				$this.data('lastTouch', now);
			});
		}
	}

	// singletap Event:
	// This is used in conjuction with doubletap when both events are needed on the same element
	$.event.special.singletap = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject),
				origTarget = null,
				startTime  = null;

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					startTime = new Date().getTime();
					origTarget = e.target;
				}
			}).bind(settings.endevent, function(e) {
				if(e.target == origTarget)
				{
					settings.tap_timer = window.setTimeout(function() {
						if(!$this.data('doubletapped') && !$this.data('tapheld'))
						{
							triggerCustomEvent(thisObject, 'singletap', e);
						}
					}, settings.doubletap_int);
				}
			});
		}
	}

	// tap Event:
	$.event.special.tap = {
		setup: function() {
			var thisObject = this,
				$this = $(thisObject),
			    started = false,
				origTarget = null,
				start_time,
				start_pos = { x : 0, y : 0 };

			$this.bind(settings.startevent, function(e) {
				if(e.which && e.which !== 1)
				{
					return false;
				}
				else
				{
					started = true;
					start_pos.x = (settings.touch_capabale) ? e.targetTouches[0].pageX : e.pageX;
					start_pos.y = (settings.touch_capabale) ? e.targetTouches[0].pageY : e.pageY;
					start_time = new Date().getTime();
					origTarget = e.target;
				}
			}).bind(settings.endevent, function(e) {
				// Only trigger if they've started, and the target matches:
				var end_x = (settings.touch_capabale) ? e.targetTouches[0].pageX : e.pageX,
					end_y = (settings.touch_capabale) ? e.targetTouches[0].pageY : e.pageY;

				if(origTarget == e.target && started && ((new Date().getTime() - start_time) < settings.taphold_threshold) && (start_pos.x == end_x && start_pos.y == end_y))
				{
					triggerCustomEvent(thisObject, 'tap', e);
				}
			});
		}
	};

	// swipe Event (also handles swipeup, swiperight, swipedown and swipeleft):
	$.event.special.swipe = {
		setup: function() {
			var thisObject = this,
			    $this = $(thisObject),
				originalCoord = { x: 0, y: 0 },
			    finalCoord    = { x: 0, y: 0 };

			// Screen touched, store the original coordinate
			function touchStart(event)
			{
				originalCoord.x = (settings.touch_capable) ? event.targetTouches[0].pageX : event.pageX;
				originalCoord.y = (settings.touch_capable) ? event.targetTouches[0].pageY : event.pageY;
				finalCoord.x = originalCoord.x
				finalCoord.y = originalCoord.y
			}

			// Store coordinates as finger is swiping
			function touchMove(event)
			{
				event.preventDefault();
				finalCoord.x = (settings.touch_capable) ? event.targetTouches[0].pageX : event.pageX;
				finalCoord.y = (settings.touch_capable) ? event.targetTouches[0].pageY : event.pageY;
				window.clearTimeout(settings.hold_timer);
			}

			function touchEnd(e)
			{
				var swipedir;
				if(originalCoord.y > finalCoord.y && (originalCoord.y - finalCoord.y > settings.swipe_v_threshold)) { swipedir = 'swipeup'; }
				if(originalCoord.x < finalCoord.x && (finalCoord.x - originalCoord.x > settings.swipe_h_threshold)) { swipedir = 'swiperight'; }
				if(originalCoord.y < finalCoord.y && (finalCoord.y - originalCoord.y > settings.swipe_v_threshold)) { swipedir = 'swipedown'; }
				if(originalCoord.x > finalCoord.x && (originalCoord.x - finalCoord.x > settings.swipe_h_threshold)) { swipedir = 'swipeleft'; }
				if(swipedir != undefined)
				{
					$this.trigger('swipe').trigger(swipedir);
				}
			}

			// Add gestures to all swipable areas
			thisObject.addEventListener(settings.startevent, touchStart, false);
			thisObject.addEventListener(settings.moveevent, touchMove, false);
			thisObject.addEventListener(settings.endevent, touchEnd, false);
		}
	};

	// scrollstart Event (also handles scrollend):
	$.event.special.scrollstart = {
		setup: function() {
			var thisObject = this,
				$this = $(thisObject),
				scrolling,
				timer;

			function trigger(event, state)
			{
				scrolling = state;
				triggerCustomEvent(thisObject, scrolling ? 'scrollstart' : 'scrollend', event);
			}

			// iPhone triggers scroll after a small delay; use touchmove instead
			$this.bind(settings.scrollevent, function(event) {
				if(!scrolling)
				{
					trigger(event, true);
				}

				clearTimeout(timer);
				timer = setTimeout(function() { trigger(event, false); }, 50);
			});
		}
	};

	// This is the orientation change (largely borrowed from jQuery Mobile):
	var win = $(window),
		special_event,
		get_orientation,
		last_orientation,
		initial_orientation_is_landscape,
		initial_orientation_is_default,
		portrait_map = { '0': true, '180': true };

	if(settings.orientation_support)
	{
		var ww = window.innerWidth || $(window).width(),
			wh = window.innerHeight || $(window).height(),
			landscape_threshold = 50;

		initial_orientation_is_landscape = ww > wh && (ww - wh) > landscape_threshold;
		initial_orientation_is_default = portrait_map[window.orientation];

		if((initial_orientation_is_landscape && initial_orientation_is_default) || (!initial_orientation_is_landscape && !initial_orientation_is_default))
		{
			portrait_map = { '-90': true, '90': true };
		}
	}

	$.event.special.orientationchange = special_event = {
		setup: function() {
			// If the event is supported natively, return false so that jQuery
			// will bind to the event using DOM methods.
			if(settings.orientation_support)
			{
				return false;
			}

			// Get the current orientation to avoid initial double-triggering.
			last_orientation = get_orientation();

			win.bind('throttledresize', handler);
		},
		teardown: function()
		{
			if (settings.orientation_support)
			{
				return false;
			}

			win.unbind('throttledresize', handler);
		},
		add: function(handleObj)
		{
			// Save a reference to the bound event handler.
			var old_handler = handleObj.handler;

			handleObj.handler = function(event)
			{
				event.orientation = get_orientation();
				return old_handler.apply(this, arguments);
			};
		}
	};

	// If the event is not supported natively, this handler will be bound to
	// the window resize event to simulate the orientationchange event.
	function handler()
	{
		// Get the current orientation.
		var orientation = get_orientation();

		if(orientation !== last_orientation)
		{
			// The orientation has changed, so trigger the orientationchange event.
			last_orientation = orientation;
			win.trigger( "orientationchange" );
		}
	}

	$.event.special.orientationchange.orientation = get_orientation = function() {
		var isPortrait = true,
		    elem = document.documentElement;

		if(settings.orientation_support)
		{
			isPortrait = portrait_map[window.orientation];
		}
		else
		{
			isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
		}

		return isPortrait ? 'portrait' : 'landscape';
	};

	// throttle Handler:
	$.event.special.throttledresize = {
		setup: function()
		{
			$(this).bind('resize', throttle_handler);
		},
		teardown: function()
		{
			$(this).unbind('resize', throttle_handler);
		}
	};

	var throttle = 250,
		throttle_handler = function()
		{
			curr = (new Date()).getTime();
			diff = curr - lastCall;

			if(diff >= throttle)
			{
				lastCall = curr;
				$(this).trigger('throttledresize');

			}
			else
			{
				if(heldCall)
				{
					window.clearTimeout(heldCall);
				}

				// Promise a held call will still execute
				heldCall = window.setTimeout(handler, throttle - diff);
			}
		},
		lastCall = 0,
		heldCall,
		curr,
		diff;

	// Trigger a custom event:
	function triggerCustomEvent( obj, eventType, event ) {
		var originalType = event.type;
		event.type = eventType;
		$.event.handle.call( obj, event );
		event.type = originalType;
	}

	// Correctly bind anything we've overloaded:
	$.each({
		scrollend: 'scrollstart',
		swipeup: 'swipe',
		swiperight: 'swipe',
		swipedown: 'swipe',
		swipeleft: 'swipe'
	}, function(e, srcE) {
		$.event.special[e] =
		{
			setup: function() {
				$(this).bind(srcE, $.noop);
			}
		};
	});

}) (jQuery);
<|endoftext|>


<commit_before>const url = require("url");
const WebSocket = require("ws");
var fs = require("fs"); // Node.js File System
var Transform = require("stream").Transform; // Node.js Transform stream
const util = require("util");
const Rooms = require("./rooms");

const FIVE_MEGABYTES = 5243000;

const messageHistory = "./game/bots/recentmessages.txt";

// Enum of game modes.
var Mode = {
	START_ROOM: 1,
	JOIN_ROOM: 2,
	JOIN_RANDOM: 3,
};

var wss;

/* Initializes the WebSocket on the given server. */
function start(server) {
	wss = new WebSocket.Server({ server, perMessageDeflate: false });
	wss.on("connection", onConnection);
}

/* Called when a client connects to the WebSocket. */
function onConnection(client) {
	// Set the event listeners.
	client.on("message", function(message) {onIncomingMessage(message, client)});
	client.on("close", onClose);

	client.send("Connection opened.");
}

/* Called when the server receives a message from a client. */
function onIncomingMessage(message, client) {
	try {
		// First try parsing the data as JSON.
		var json = JSON.parse(message);
		handleClientJson(client, json);
	} catch (error) {
		if (error instanceof SyntaxError) {
			// If it's not JSON, just broadcast the message.
			broadcastText(client, message);
		} else {
			// If the message was JSON, but an unrelated error happened.
			throw error;
		}
	}
}

/* Handle JSON sent from a client. */
function handleClientJson(client, json) {
	if (json.mode) {
		if (json.mode == Mode.START_ROOM) {
			startRoomWithFriends(client);
		} else if (json.mode == Mode.JOIN_ROOM) {
			joinRoomWithFriends(client, json.roomCode);
		} else if (json.mode == Mode.JOIN_RANDOM) {
			joinRandom(client);
		}
	}

	if (json.hasOwnProperty("readyToVote")) {
		Rooms.setPlayerAsReady(client, json.readyToVote);
	}

	if (json.ballot) {
		Rooms.submitBallot(client, json.ballot);
	}

	if (json.message) {
		broadcastText(client, json.message);
	}
}

/* Broadcast text to all the clients in the sender's room. */
function broadcastText(sender, message) {
	var room = Rooms.getRoomOfClient(sender);
	room.broadcast(message, sender);

	appendMessageToLog(messageHistory, message);
}

/* Called when a client closes the WebSocket connection. */
function onClose(code, reason) {
	console.log("A client disconnected. Code: " + code + ". Reason: " + reason);
	// Unfortunately, we cannot tell which client disconnected.
}

function joinRandom(client) {
	// Keep track of the newly joined client.
	var room = Rooms.getWaitingRoom();
	Rooms.addClientToRoom(client, room);
}

function startRoomWithFriends(client) {
	var code = Rooms.newRoomCode();
	var room = Rooms.getRoomByCode(code);
	Rooms.addClientToRoom(client, room);
	sendCodeToClient(code, client);
}

function sendCodeToClient(code, client) {
	var payload = {'roomCode': code};
	if (client.readyState === WebSocket.OPEN) {
		client.send(JSON.stringify(payload));
	}
}

function joinRoomWithFriends(client, roomCode) {
	if (Rooms.validCode(roomCode)) {
		var room = Rooms.getRoomByCode(roomCode);
		Rooms.addClientToRoom(client, room);
		sendJoinReceipt(client);
	} else {
		// If we can't find the room, display an error to the user.
		clientError(client, "That room does not exist.");
	}
}

// Tell the client that they have successfully joined a room.
function sendJoinReceipt(client) {
	if (client.readyState === WebSocket.OPEN) {
		client.send(JSON.stringify({"joinedRoom": true}));
	}
}

function clientError(client, message) {
	if (client.readyState === WebSocket.OPEN) {
		client.send(JSON.stringify({"error": message}));
	}
}

function appendMessageToLog(filename, message) {
	// Delete oldest messages, ten at a time
	// until the size is below an arbitrary limit
	while (fs.stat(filename).size > FIVE_MEGABYTES) {
		removeFirstLines(filename, 10);
	}

	// Append the message to the text log of recent messages
	fs.appendFile(filename, message + "\n", "utf8");
}

function removeFirstLines(filename, numLines) {
	for (var i = 0; i < numLines; i++) {
		var input = fs.createReadStream(filename);
		var output = fs.createWriteStream(filename);

		input.pipe(RemoveFirstLine()).pipe(output);
	}
}

function RemoveFirstLine(args) {
    if (! (this instanceof RemoveFirstLine)) {
        return new RemoveFirstLine(args);
    }
    Transform.call(this, args);
    this._buff = '';
    this._removed = false;
}
util.inherits(RemoveFirstLine, Transform);

RemoveFirstLine.prototype._transform = function(chunk, encoding, done) {
    if (this._removed) { // if already removed
        this.push(chunk); // just push through buffer
    } else {
        // collect string into buffer
        this._buff += chunk.toString();

        // check if string has newline symbol
        if (this._buff.indexOf('\n') !== -1) {
            // push to stream skipping first line
            this.push(this._buff.slice(this._buff.indexOf('\n') + 2));
            // clear string buffer
            this._buff = null;
            // mark as removed
            this._removed = true;
        }
    }
    done();
};

module.exports = {start: start};
<commit_msg>Resolve merge conflict<commit_after>const url = require("url");
const WebSocket = require("ws");
var fs = require("fs"); // Node.js File System
var Transform = require("stream").Transform; // Node.js Transform stream
const util = require("util");
const Rooms = require("./rooms");

const FIVE_MEGABYTES = 5243000;

const messageHistory = "./game/bots/recentmessages.txt";

// Enum of game modes.
var Mode = {
	START_ROOM: 1,
	JOIN_ROOM: 2,
	JOIN_RANDOM: 3,
};

var wss;

/* Initializes the WebSocket on the given server. */
function start(server) {
	wss = new WebSocket.Server({ server, perMessageDeflate: false });
	wss.on("connection", onConnection);
}

/* Called when a client connects to the WebSocket. */
function onConnection(client) {
	// Set the event listeners.
	client.on('message', function(message) {onIncomingMessage(message, client)});
	client.on('close', function(code, reason) {onClose(code, reason, client)});

	client.send("Connection opened.");
}

/* Called when the server receives a message from a client. */
function onIncomingMessage(message, client) {
	try {
		// First try parsing the data as JSON.
		var json = JSON.parse(message);
		handleClientJson(client, json);
	} catch (error) {
		if (error instanceof SyntaxError) {
			// If it's not JSON, just broadcast the message.
			broadcastText(client, message);
		} else {
			// If the message was JSON, but an unrelated error happened.
			throw error;
		}
	}
}

/* Handle JSON sent from a client. */
function handleClientJson(client, json) {
	if (json.mode) {
		if (json.mode == Mode.START_ROOM) {
			startRoomWithFriends(client);
		} else if (json.mode == Mode.JOIN_ROOM) {
			joinRoomWithFriends(client, json.roomCode);
		} else if (json.mode == Mode.JOIN_RANDOM) {
			joinRandom(client);
		}
	}

	if (json.hasOwnProperty("readyToVote")) {
		Rooms.setPlayerAsReady(client, json.readyToVote);
	}

	if (json.ballot) {
		Rooms.submitBallot(client, json.ballot);
	}

	if (json.message) {
		broadcastText(client, json.message);
	}
}

/* Broadcast text to all the clients in the sender's room. */
function broadcastText(sender, message) {
	var room = Rooms.getRoomOfClient(sender);
	room.broadcast(message, sender);

	appendMessageToLog(messageHistory, message);
}

/* Called when a client closes the WebSocket connection. */
<<<<<<< HEAD
function onClose(code, reason) {
	console.log("A client disconnected. Code: " + code + ". Reason: " + reason);
	// Unfortunately, we cannot tell which client disconnected.
=======
function onClose(code, reason, sender) {
    var room = Rooms.getRoomOfClient(sender);
    room.remove(sender);
    console.log("A client disconnected. Code: " + code + ". Reason: " + reason);
>>>>>>> e47e200f665cb6aa65f9407439f4b1b588670db9
}

function joinRandom(client) {
	// Keep track of the newly joined client.
	var room = Rooms.getWaitingRoom();
	Rooms.addClientToRoom(client, room);
}

function startRoomWithFriends(client) {
	var code = Rooms.newRoomCode();
	var room = Rooms.getRoomByCode(code);
	Rooms.addClientToRoom(client, room);
	sendCodeToClient(code, client);
}

function sendCodeToClient(code, client) {
	var payload = {'roomCode': code};
	if (client.readyState === WebSocket.OPEN) {
		client.send(JSON.stringify(payload));
	}
}

function joinRoomWithFriends(client, roomCode) {
	if (Rooms.validCode(roomCode)) {
		var room = Rooms.getRoomByCode(roomCode);
		Rooms.addClientToRoom(client, room);
		sendJoinReceipt(client);
	} else {
		// If we can't find the room, display an error to the user.
		clientError(client, "That room does not exist.");
	}
}

// Tell the client that they have successfully joined a room.
function sendJoinReceipt(client) {
	if (client.readyState === WebSocket.OPEN) {
		client.send(JSON.stringify({"joinedRoom": true}));
	}
}

function clientError(client, message) {
	if (client.readyState === WebSocket.OPEN) {
		client.send(JSON.stringify({"error": message}));
	}
}

function appendMessageToLog(filename, message) {
	// Delete oldest messages, ten at a time
	// until the size is below an arbitrary limit
	while (fs.stat(filename).size > FIVE_MEGABYTES) {
		removeFirstLines(filename, 10);
	}

	// Append the message to the text log of recent messages
	fs.appendFile(filename, message + "\n", "utf8");
}

function removeFirstLines(filename, numLines) {
	for (var i = 0; i < numLines; i++) {
		var input = fs.createReadStream(filename);
		var output = fs.createWriteStream(filename);

		input.pipe(RemoveFirstLine()).pipe(output);
	}
}

function RemoveFirstLine(args) {
    if (! (this instanceof RemoveFirstLine)) {
        return new RemoveFirstLine(args);
    }
    Transform.call(this, args);
    this._buff = '';
    this._removed = false;
}
util.inherits(RemoveFirstLine, Transform);

RemoveFirstLine.prototype._transform = function(chunk, encoding, done) {
    if (this._removed) { // if already removed
        this.push(chunk); // just push through buffer
    } else {
        // collect string into buffer
        this._buff += chunk.toString();

        // check if string has newline symbol
        if (this._buff.indexOf('\n') !== -1) {
            // push to stream skipping first line
            this.push(this._buff.slice(this._buff.indexOf('\n') + 2));
            // clear string buffer
            this._buff = null;
            // mark as removed
            this._removed = true;
        }
    }
    done();
};

module.exports = {start: start};
<|endoftext|>


<commit_before>// ==UserScript==
// @name          Kongregate Forum Muting
// @namespace     ventero.de
// @include       http://www.kongregate.com/forums/*
// @include       http://www.kongregate.com/accounts/*
// @description   Allows you to mute users in the Kongregate forums. All posts by muted users get hidden.
// @author        Ventero
// @version       1.3
// @date          13.10.2010
// ==/UserScript==

// Written by Ventero (http://www.kongregate.com/accounts/Ventero) 05/23/09
// Copyright (c) 2009-2012 Ventero, licensed under MIT/X11 license
// http://www.opensource.org/licenses/mit-license.php

/* Changelog
 *
 * 1.0: Initial release
 * 1.1: Mute/Unmute no longer disappears after flagging a post
 * 1.2: Added ability to mute users from their profiles
 * 1.3: Added "Hide post" button to posts by muted users you're manually viewing
 */

var MUTED = "kong_forum_muted_users";
var mutedUsers = [];

function saveMutings(){
  window.setTimeout(function(){
    GM_setValue(MUTED, mutedUsers.join("|"));
  }, 0);
}

function isMuted(user){
  return (mutedUsers.indexOf(user) >= 0);
}

function loadMutings(){
  var saved = GM_getValue(MUTED, "");
  if(!saved) return;
  mutedUsers = saved.split("|");
}

function muteUser(user){
  if(isMuted(user)) return;

  mutedUsers.push(user);
  saveMutings();
}

function unmuteUser(user){
  var idx = mutedUsers.indexOf(user);
  if(idx == -1) return;

  mutedUsers.splice(idx, 1);
  saveMutings();
}

function addButton(postsRow, text, callback){
  var vcard = postsRow.getElementsByClassName("vcard")[0];
  if(!vcard) return;

  removeButton(vcard);
  vcard.innerHTML += '
' + text + ''
  vcard.getElementsByClassName("mutelink")[0]
       .addEventListener("click", callback, false);
}

function removeButton(vcard){
  var button = vcard.getElementsByClassName("mutelink")[0];
  if(button) button.parentNode.removeChild(button);

  var clear = vcard.getElementsByClassName("clear")[0];
  if(clear) clear.parentNode.removeChild(clear);
}

function addMuteButton(postsRow, username){
  addButton(postsRow, "Mute user", function(e){addMuting(username);e.preventDefault();});
}

function addUnmuteButton(postsRow, username){
  addButton(postsRow, "Unmute user", function(e){removeMuting(username);e.preventDefault();});
}

function addViewPostButton(postsRow, username){
  var body = postsRow.getElementsByClassName("body")[0];
  if(!body) return;

  body.innerHTML += '
View post
';
  body.getElementsByClassName("view-post")[0]
      .addEventListener("click", function(e){
        viewPost(this.parentNode.parentNode.parentNode, username, true);
        e.preventDefault();
      }, false);
}

function addHidePostButton(postsRow, username){
  var body = postsRow.getElementsByClassName("entry-content")[0];
  if(!body) return;

  body.innerHTML = 'Hide post
' + body.innerHTML;
  body.getElementsByClassName("hide-post")[0]
      .addEventListener("click", function(e){
        hidePost(this.parentNode.parentNode.parentNode, username);
        e.preventDefault();
      }, false);
}

function removeViewPostButton(postsRow){
  var viewPostDiv = postsRow.getElementsByClassName("entry-content muted-content")[0];
  if(viewPostDiv) viewPostDiv.parentNode.removeChild(viewPostDiv);
}

function removeHidePostButton(postsRow){
  var hidePostButton = postsRow.getElementsByClassName("hide-post")[0];
  if(hidePostButton) hidePostButton.parentNode.removeChild(hidePostButton);
}

function addBlankVCard(postsRow, username){
  postsRow.innerHTML = '' + '' + username + '' + '	' + postsRow.innerHTML;
}

function removeBlankVCard(postsRow){
  var blankVCard = postsRow.getElementsByClassName("author blank")[0];
  if(blankVCard) postsRow.removeChild(blankVCard);
}

function hideVCard(postsRow){
  var vcard = postsRow.getElementsByClassName("vcard")[0];
  if(vcard) vcard.style.display = "none";
}

function showVCard(postsRow){
  var vcard = postsRow.getElementsByClassName("vcard")[0];
  if(vcard) vcard.style.display = "";
}

function hideBody(postsRow){
  var postDiv = postsRow.getElementsByClassName("entry-content")[0]
  if(postDiv) postDiv.style.display = "none";
}

function showBody(postsRow){
  var postDiv = postsRow.getElementsByClassName("entry-content")[0]
  if(postDiv) postDiv.style.display = "";
}

function getUsername(post){
  var avatar = post.getElementsByClassName("user_avatar")[0];
  return avatar && avatar.title;
}

function doWithEveryPost(callback){
  var posts = document.getElementsByClassName("post hentry");

  var current, username
  for(var i = 0, l = posts.length; i < l; i++){
    current = posts[i];
    username = getUsername(current);
    if(username) callback(current, username);
  }
}

function viewPost(postsRow, username, showHide){
  // called as callback from the "View Post" button
  removeBlankVCard(postsRow);
  removeViewPostButton(postsRow);
  removeHidePostButton(postsRow);
  showBody(postsRow);
  showVCard(postsRow);
  if(showHide) addHidePostButton(postsRow, username);
}

function hidePost(postsRow, username){
  // sets up posts by muted users
  removeHidePostButton(postsRow);
  hideVCard(postsRow);
  hideBody(postsRow);
  addBlankVCard(postsRow, username);
  addViewPostButton(postsRow, username);
  addUnmuteButton(postsRow, username);
}

function initialCheck(postsRow, username){
  if(isMuted(username)){
    // user is muted, hide post
    hidePost(postsRow, username);
  } else {
    // show mute user button
    addMuteButton(postsRow, username);
  }
}

function addMuting(username){
  muteUser(username);
  doWithEveryPost(function(post, user){
    if(user == username){
      hidePost(post, username);
    }
  });
}

function removeMuting(username){
  unmuteUser(username);
  doWithEveryPost(function(post, user){
    if(user == username){
      viewPost(post, username);
      addMuteButton(post, user);
    }
  });
}

function addProfileMuteLink(user){
  var li = document.getElementById("forummute");
  if(li) li.parentNode.removeChild(li);
  li = document.createElement("li");
  li.setAttribute("id", "forummute");

  var a = document.createElement("a");
  a.setAttribute("href", "#");

  li.appendChild(a);
  rellinks.appendChild(li);

  var muted = isMuted(user);
  a.innerHTML = (muted ? "forum unmute" : "forum mute");
  a.addEventListener("click", function(e){
    muted ? unmuteUser(user) : muteUser(user);
    addProfileMuteLink(user);
    e.preventDefault();
  }, false);
}

if(typeof GM_setValue !== "function" || /Chrome/i.test(navigator.appVersion)){
  GM_setValue = function(a,b){localStorage.setItem(a,b)}
  GM_getValue = function(a,b){
    return ((a in localStorage) ? localStorage.getItem(a) : b)
  }
}
loadMutings();

if(location.pathname.substring(0, 10) == "/accounts/"){
  var rellinks = document.getElementById("relationship_links");
  if(!rellinks) return;

  var user = location.pathname.split("/")[2];
  if(!user) return;

  addProfileMuteLink(user);
} else {
  var head = document.getElementsByTagName("head")[0];
  var style = document.createElement("style");
  style.innerHTML = "a.view-post, a.hide-post {font-size: 0.8em;}\n" +
                    "tr.post span.muted a {font-size: 0.8em; color:#666666;}\n" +
                    "a.mutelink {font-weight: normal;}";
  head.appendChild(style);

  var table = document.querySelector("table.posts");
  if(table) {
    table.addEventListener("DOMNodeInserted", function(a){
      if(a.target.id && a.target.id.indexOf("posts") == 0) {
        initialCheck(a.target, getUsername(a.target));
      }
    }, false);
  }

  doWithEveryPost(initialCheck);
}
<commit_msg>Fix forum muting.<commit_after>// ==UserScript==
// @name          Kongregate Forum Muting
// @namespace     ventero.de
// @include       http://www.kongregate.com/forums/*
// @include       http://www.kongregate.com/accounts/*
// @description   Allows you to mute users in the Kongregate forums. All posts by muted users get hidden.
// @author        Ventero
// @version       1.4
// @date          2014-08-19
// @grant         GM_getValue
// @grant         GM_setValue
// ==/UserScript==

// Written by Ventero (http://www.kongregate.com/accounts/Ventero) 05/23/09
// Copyright (c) 2009-2012 Ventero, licensed under MIT/X11 license
// http://www.opensource.org/licenses/mit-license.php

/* Changelog
 *
 * 1.0: Initial release
 * 1.1: Mute/Unmute no longer disappears after flagging a post
 * 1.2: Added ability to mute users from their profiles
 * 1.3: Added "Hide post" button to posts by muted users you're manually viewing
 */

var MUTED = "kong_forum_muted_users";
var mutedUsers = [];

function saveMutings(){
  window.setTimeout(function(){
    GM_setValue(MUTED, mutedUsers.join("|"));
  }, 0);
}

function isMuted(user){
  return (mutedUsers.indexOf(user) >= 0);
}

function loadMutings(){
  var saved = GM_getValue(MUTED, "");
  if(!saved) return;
  mutedUsers = saved.split("|");
}

function muteUser(user){
  if(isMuted(user)) return;

  mutedUsers.push(user);
  saveMutings();
}

function unmuteUser(user){
  var idx = mutedUsers.indexOf(user);
  if(idx == -1) return;

  mutedUsers.splice(idx, 1);
  saveMutings();
}

function addButton(postsRow, text, callback){
  var vcard = postsRow.getElementsByClassName("form_ctrls mtm regtextSml")
  if(!vcard) return;

  removeButton(vcard);
  vcard.innerHTML += '
' + text + ''
  vcard.getElementsByClassName("mutelink")[0]
       .addEventListener("click", callback, false);
}

function removeButton(vcard){
  var button = vcard.getElementsByClassName("mutelink")[0];
  if(button) button.parentNode.removeChild(button);

  var clear = vcard.getElementsByClassName("clear")[0];
  if(clear) clear.parentNode.removeChild(clear);
}

function addMuteButton(postsRow, username){
  addButton(postsRow, "Mute user", function(e){addMuting(username);e.preventDefault();});
}

function addUnmuteButton(postsRow, username){
  addButton(postsRow, "Unmute user", function(e){removeMuting(username);e.preventDefault();});
}

function addViewPostButton(postsRow, username){
  var body = postsRow.getElementsByClassName("body")[0];
  if(!body) return;

  body.innerHTML += '
View post
';
  body.getElementsByClassName("view-post")[0]
      .addEventListener("click", function(e){
        viewPost(this.parentNode.parentNode.parentNode, username, true);
        e.preventDefault();
      }, false);
}

function addHidePostButton(postsRow, username){
  var body = postsRow.getElementsByClassName("entry-content")[0];
  if(!body) return;

  body.innerHTML = 'Hide post
' + body.innerHTML;
  body.getElementsByClassName("hide-post")[0]
      .addEventListener("click", function(e){
        hidePost(this.parentNode.parentNode.parentNode, username);
        e.preventDefault();
      }, false);
}

function removeViewPostButton(postsRow){
  var viewPostDiv = postsRow.getElementsByClassName("entry-content muted-content")[0];
  if(viewPostDiv) viewPostDiv.parentNode.removeChild(viewPostDiv);
}

function removeHidePostButton(postsRow){
  var hidePostButton = postsRow.getElementsByClassName("hide-post")[0];
  if(hidePostButton) hidePostButton.parentNode.removeChild(hidePostButton);
}

function addBlankVCard(postsRow, username){
  postsRow.innerHTML = '' + '' + username + '' + '	' + postsRow.innerHTML;
}

function removeBlankVCard(postsRow){
  var blankVCard = postsRow.getElementsByClassName("author blank")[0];
  if(blankVCard) postsRow.removeChild(blankVCard);
}

function hideVCard(postsRow){
  var vcard = postsRow.getElementsByClassName("vcard")[0];
  if(vcard) vcard.style.display = "none";
}

function showVCard(postsRow){
  var vcard = postsRow.getElementsByClassName("vcard")[0];
  if(vcard) vcard.style.display = "";
}

function hideBody(postsRow){
  var postDiv = postsRow.getElementsByClassName("entry-content")[0]
  if(postDiv) postDiv.style.display = "none";
}

function showBody(postsRow){
  var postDiv = postsRow.getElementsByClassName("entry-content")[0]
  if(postDiv) postDiv.style.display = "";
}

function getUsername(post){
  var avatar = post.getElementsByClassName("user_avatar")[0];
  return avatar && avatar.title;
}

function doWithEveryPost(callback){
  var posts = document.getElementsByClassName("post hentry");

  var current, username
  for(var i = 0, l = posts.length; i < l; i++){
    current = posts[i];
    username = getUsername(current);
    if(username) callback(current, username);
  }
}

function viewPost(postsRow, username, showHide){
  // called as callback from the "View Post" button
  removeBlankVCard(postsRow);
  removeViewPostButton(postsRow);
  removeHidePostButton(postsRow);
  showBody(postsRow);
  showVCard(postsRow);
  if(showHide) addHidePostButton(postsRow, username);
}

function hidePost(postsRow, username){
  // sets up posts by muted users
  removeHidePostButton(postsRow);
  hideVCard(postsRow);
  hideBody(postsRow);
  addBlankVCard(postsRow, username);
  addViewPostButton(postsRow, username);
  addUnmuteButton(postsRow, username);
}

function initialCheck(postsRow, username){
  if(isMuted(username)){
    // user is muted, hide post
    hidePost(postsRow, username);
  } else {
    // show mute user button
    addMuteButton(postsRow, username);
  }
}

function addMuting(username){
  muteUser(username);
  doWithEveryPost(function(post, user){
    if(user == username){
      hidePost(post, username);
    }
  });
}

function removeMuting(username){
  unmuteUser(username);
  doWithEveryPost(function(post, user){
    if(user == username){
      viewPost(post, username);
      addMuteButton(post, user);
    }
  });
}

function addProfileMuteLink(user){
  var li = document.getElementById("forummute");
  if(li) li.parentNode.removeChild(li);
  li = document.createElement("li");
  li.setAttribute("id", "forummute");

  var a = document.createElement("a");
  a.setAttribute("href", "#");

  li.appendChild(a);
  rellinks.appendChild(li);

  var muted = isMuted(user);
  a.innerHTML = (muted ? "forum unmute" : "forum mute");
  a.addEventListener("click", function(e){
    muted ? unmuteUser(user) : muteUser(user);
    addProfileMuteLink(user);
    e.preventDefault();
  }, false);
}

if(typeof GM_setValue !== "function" || /Chrome/i.test(navigator.appVersion)){
  GM_setValue = function(a,b){localStorage.setItem(a,b)}
  GM_getValue = function(a,b){
    return ((a in localStorage) ? localStorage.getItem(a) : b)
  }
}
loadMutings();

if(location.pathname.substring(0, 10) == "/accounts/"){
  var rellinks = document.getElementById("relationship_links");
  if(!rellinks) return;

  var user = location.pathname.split("/")[2];
  if(!user) return;

  addProfileMuteLink(user);
} else {
  var head = document.getElementsByTagName("head")[0];
  var style = document.createElement("style");
  style.innerHTML = "a.view-post, a.hide-post {font-size: 0.8em;}\n" +
                    "tr.post span.muted a {font-size: 0.8em; color:#666666;}\n" +
                    "a.mutelink {font-weight: normal;}";
  head.appendChild(style);

  var table = document.querySelector("table.posts");
  if(table) {
    table.addEventListener("DOMNodeInserted", function(a){
      if(a.target.id && a.target.id.indexOf("posts") == 0) {
        initialCheck(a.target, getUsername(a.target));
      }
    }, false);
  }

  doWithEveryPost(initialCheck);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * 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.
 *
 */

define(function (require, exports) {
    "use strict";

    var descriptor = require("adapter/ps/descriptor"),
        document = require("adapter/lib/document");

    var events = require("../events"),
        locks = require("js/locks"),
        Promise = require("bluebird");

    /**
     * Activate the already-open document at the given index.
     *
     * @param {number} index The index of the document to select
     * @return {Promise}
     */
    var selectDocumentCommand = function (index) {
        return descriptor.playObject(document.select(document.referenceBy.index(index)))
            .then(function () {
                var payload = {
                    selectedDocumentIndex: index
                };

                this.dispatch(events.documents.SELECT_DOCUMENT, payload);
            }.bind(this));
    };

    /**
     * Activate the already-open document at the given offset from the index of
     * the currently active document.
     *
     * @param {number} offset The index-offset of the document to activate
     *  relative to the currently active document
     * @return {Promise}
     */
    var scrollDocumentsCommand = function (offset) {
        return descriptor.playObject(document.select(document.referenceBy.offset(offset)))
            .then(function () {
                var payload = {
                    offset: offset
                };

                this.dispatch(events.documents.SCROLL_DOCUMENTS, payload);
            }.bind(this));
    };

    /**
     * Fetch the set of currently open documents from Photoshop
     *
     * @return {Promise}
     */
    var updateDocumentListCommand = function () {
        return descriptor.getProperty("application", "numberOfDocuments")
            .then(function (docCount) {
                var documentGets = [];
                for (var i = 1; i <= docCount; i++) {
                    documentGets.push(descriptor.get(document.referenceBy.index(i)));
                }

                var allDocumentsPromise = Promise.all(documentGets),
                    currentDocIndexPromise = descriptor.getProperty(document.referenceBy.current, "itemIndex"),
                    currentDocIDPromise = descriptor.getProperty(document.referenceBy.current, "documentID");

                return Promise.join(allDocumentsPromise, currentDocIndexPromise, currentDocIDPromise,
                    function (documents, currentIndex, currentID) {
                        var payload = {
                            selectedDocumentIndex: currentIndex,
                            selectedDocumentID: currentID,
                            documents: documents
                        };
                        this.dispatch(events.documents.DOCUMENTS_UPDATED, payload);
                    }.bind(this));
            }.bind(this));
    };

    var selectDocument = {
        command: selectDocumentCommand,
        writes: locks.ALL_LOCKS
    };

    var scrollDocuments = {
        command: scrollDocumentsCommand,
        writes: locks.ALL_LOCKS
    };

    var updateDocumentList = {
        command: updateDocumentListCommand,
        writes: locks.ALL_LOCKS
    };

    exports.selectDocument = selectDocument;
    exports.scrollDocuments = scrollDocuments;
    exports.updateDocumentList = updateDocumentList;
});
<commit_msg>Don't try to get document info if there are no documents open<commit_after>/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * 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.
 *
 */

define(function (require, exports) {
    "use strict";

    var descriptor = require("adapter/ps/descriptor"),
        document = require("adapter/lib/document");

    var events = require("../events"),
        locks = require("js/locks"),
        Promise = require("bluebird");

    /**
     * Activate the already-open document at the given index.
     *
     * @param {number} index The index of the document to select
     * @return {Promise}
     */
    var selectDocumentCommand = function (index) {
        return descriptor.playObject(document.select(document.referenceBy.index(index)))
            .then(function () {
                var payload = {
                    selectedDocumentIndex: index
                };

                this.dispatch(events.documents.SELECT_DOCUMENT, payload);
            }.bind(this));
    };

    /**
     * Activate the already-open document at the given offset from the index of
     * the currently active document.
     *
     * @param {number} offset The index-offset of the document to activate
     *  relative to the currently active document
     * @return {Promise}
     */
    var scrollDocumentsCommand = function (offset) {
        return descriptor.playObject(document.select(document.referenceBy.offset(offset)))
            .then(function () {
                var payload = {
                    offset: offset
                };

                this.dispatch(events.documents.SCROLL_DOCUMENTS, payload);
            }.bind(this));
    };

    /**
     * Fetch the set of currently open documents from Photoshop
     *
     * @return {Promise}
     */
    var updateDocumentListCommand = function () {
        return descriptor.getProperty("application", "numberOfDocuments")
            .then(function (docCount) {
                var documentGets = [];
                for (var i = 1; i <= docCount; i++) {
                    documentGets.push(descriptor.get(document.referenceBy.index(i)));
                }

                if (docCount === 0)
                    return;

                var allDocumentsPromise = Promise.all(documentGets),
                    currentDocIndexPromise = descriptor.getProperty(document.referenceBy.current, "itemIndex"),
                    currentDocIDPromise = descriptor.getProperty(document.referenceBy.current, "documentID");

                return Promise.join(allDocumentsPromise, currentDocIndexPromise, currentDocIDPromise,
                    function (documents, currentIndex, currentID) {
                        var payload = {
                            selectedDocumentIndex: currentIndex,
                            selectedDocumentID: currentID,
                            documents: documents
                        };
                        this.dispatch(events.documents.DOCUMENTS_UPDATED, payload);
                    }.bind(this));
            }.bind(this));
    };

    var selectDocument = {
        command: selectDocumentCommand,
        writes: locks.ALL_LOCKS
    };

    var scrollDocuments = {
        command: scrollDocumentsCommand,
        writes: locks.ALL_LOCKS
    };

    var updateDocumentList = {
        command: updateDocumentListCommand,
        writes: locks.ALL_LOCKS
    };

    exports.selectDocument = selectDocument;
    exports.scrollDocuments = scrollDocuments;
    exports.updateDocumentList = updateDocumentList;
});
<|endoftext|>


<commit_before>var http = require('http')
  , https = require('https');

  //////////////////////
 // gdata CORS proxy //
//////////////////////

http.createServer(function (req, res) {
  console.log('\nREQ.URL:'+req.url);
  console.log('\nREQ.METHOD:'+req.method);
  console.log('\nREQ.HEADERS:'+JSON.stringify(req.headers));
  var options =
    { 'host': 'docs.google.com'
    , 'port': 443
    , 'method': req.method
    , 'path': req.url
    , 'headers': req.headers
    };
  var req2 = https.request(options, function(res2) {
    var responseHeaders = res2.headers;
    //add CORS to response:
    if(req.headers['origin']) {
      responseHeaders['Access-Control-Allow-Origin'] = req.headers['origin'];
    } else {
      responseHeaders['Access-Control-Allow-Origin'] = '*';
    }

    if(req.headers['access-control-request-method']) {
      responseHeaders['Access-Control-Allow-Methods'] = req.headers['access-control-request-method'];
    } else {
      responseHeaders['Access-Control-Allow-Methods'] = 'GET, PUT, DELETE';
    }
    if(req.headers['access-control-request-headers']) {
      responseHeaders['Access-Control-Allow-Headers'] = req.headers['access-control-request-headers'];
    } else {
      responseHeaders['Access-Control-Allow-Headers'] = 'Origin, Content-Type, Authorization';
    }
    responseHeaders['Access-Control-Allow-Credentials'] = 'true';
    //replace status with 200:
    responseHeaders['X-Status'] = res2.statusCode;
    console.log('\nRES.HEADERS:'+JSON.stringify(responseHeaders));
    res.writeHead(200, responseHeaders);
    res.write('responding:');
    res2.setEncoding('utf8');
    res2.on('data', function (chunk) {
      console.log(chunk);
      res.write(chunk);
      res.end(':responding');
    });
  });
  req2.end();
}).listen(9002);
<commit_msg>further proxy cleaning<commit_after>var http = require('http')
  , https = require('https');

  //////////////////////
 // gdata CORS proxy //
//////////////////////

http.createServer(function (req, res) {
  console.log('\nREQ.URL:'+req.url);
  console.log('\nREQ.METHOD:'+req.method);
  console.log('\nREQ.HEADERS:'+JSON.stringify(req.headers));
  var options =
    { 'host': 'docs.google.com'
    , 'port': 443
    , 'method': req.method
    , 'path': req.url
    , 'headers': req.headers
    };
  var req2 = https.request(options, function(res2) {
    var responseHeaders = res2.headers;
    //add CORS to response:
    if(req.headers['origin']) {
      responseHeaders['Access-Control-Allow-Origin'] = req.headers['origin'];
    } else {
      responseHeaders['Access-Control-Allow-Origin'] = '*';
    }

    if(req.headers['access-control-request-method']) {
      responseHeaders['Access-Control-Allow-Methods'] = req.headers['access-control-request-method'];
    } else {
      responseHeaders['Access-Control-Allow-Methods'] = 'GET, PUT, DELETE';
    }
    if(req.headers['access-control-request-headers']) {
      responseHeaders['Access-Control-Allow-Headers'] = req.headers['access-control-request-headers'];
    } else {
      responseHeaders['Access-Control-Allow-Headers'] = 'Origin, Content-Type, Authorization';
    }
    responseHeaders['Access-Control-Allow-Credentials'] = 'true';
    //replace status with 200:
    responseHeaders['X-Status'] = res2.statusCode;
    console.log('\nRES.HEADERS:'+JSON.stringify(responseHeaders));
    res.writeHead(200, responseHeaders);
    res2.setEncoding('utf8');
    res2.on('data', function (chunk) {
      console.log(chunk);
      res.write(chunk);
      //res.end();
    });
  });
  req2.end();
}).listen(9002);
<|endoftext|>


<commit_before>(function() {

    if (window.cordova && typeof require !== 'undefined') {
        cordova.require('com.ludei.social.common.Social'); //force dependency load
    }
    var Cocoon = window.Cocoon;

    /**
     * Cocoon Social Interface for the Game Center Extension.
     * @namespace Cocoon.Social.GameCenter
     */
    Cocoon.define("Cocoon.Social", function(extension) {

        extension.GameCenterExtension = function() {

            this.serviceName = "LDGameCenterPlugin";
            this.onGameCenterLoginStateChanged = new Cocoon.Signal();
            this.on = this.onGameCenterLoginStateChanged.expose();
            document.addEventListener('deviceready', function() {
                this.init();
            }.bind(this));
            return this;
        };

        extension.GameCenterExtension.prototype = {

            _currentPlayer: null,

            init: function() {
                var me = this;
                Cocoon.exec(this.serviceName, "setListener", [], function(player) {
                    me._currentPlayer = player;
                    me.onGameCenterLoginStateChanged.emit("loginStatusChanged", [player]);
                });
            },

            /**
             * Returns a Cocoon Social Interface for the Game Center Extension.
             * You can use the Game Center extension in two ways, with 1:1 official API equivalent or with the CocoonJS API abstraction.
             * @function getSocialInterface
             * @memberOf Cocoon.Social.GameCenter
             * @see Cocoon.Social.Interface
             * @returns {Cocoon.Social.Interface}
             */
            getSocialInterface: function() {
                if (!this._socialService) {
                    this._socialService = new Cocoon.Social.SocialGamingServiceGameCenter(this);
                }
                return this._socialService;
            },

            /**
             * Returns a Cocoon Multiplayer interface for the Game Center Service.
             * @function getMultiplayerInterface
             * @memberOf Cocoon.Social.GameCenter
             * @returns {Cocoon.Multiplayer.MultiplayerService}
             */
            getMultiplayerInterface: function() {
                return Cocoon.Multiplayer.GameCenter;
            },

            isLoggedIn: function() {
                return this._currentPlayer && this._currentPlayer.isAuthenticated;
            },

            /**
             * Authenticates the user.
             * @function login
             * @memberOf Cocoon.Social.GameCenter
             * @params {function} callback The callback function. Response params: Cocoon.Social.GameCenter.LocalPlayer and error.
             */
            login: function(callback) {
                var me = this;
                Cocoon.exec(this.serviceName, "login", [], function(response) {
                    me._currentPlayer = response;
                    if (callback) {
                        callback(response, null);
                    }
                }, function(params) {
                    me._currentPlayer = params[0];
                    if (callback) {
                        callback(me._currentPlayer, params[1]);
                    }
                });
            },

            /**
             * Synchronous accessor for the current authResponse.
             * @function getLocalPlayer
             * @memberOf Cocoon.Social.GameCenter
             * @returns {Cocoon.Social.GameCenter.LocalPlayer} Current Local Player data.
             */
            getLocalPlayer: function() {
                return this._currentPlayer;
            },

            /**
             * Loads the players of the provided identifiers.
             * @function loadPlayers
             * @memberOf Cocoon.Social.GameCenter
             * @param {array} playerIDs Array of player identifiers.
             * @param {function} callback The callback function. It receives the following parameters:
             * - Array of {@link Cocoon.Social.GameCenter.Player}.
             * - Error.
             */
            loadPlayers: function(playerIDs, callback) {
                Cocoon.exec(this.serviceName, "loadPlayers", [playerIDs], function(players) {
                    callback(players, null);
                }, function(error) {
                    callback(null, error);
                });
            },

            /**
             * Loads the friends of the current logged in user.
             * @function loadFriends
             * @memberOf Cocoon.Social.GameCenter
             * @param {function} callback The callback function. It receives the following parameters:
             * - Array of {@link Cocoon.Social.GameCenter.Player}.
             * - Error.
             */
            loadFriends: function(callback) {
                Cocoon.exec(this.serviceName, "loadFriends", [], function(players) {
                    callback(players, null);
                }, function(error) {
                    callback(null, error);
                });
            },

            /**
             * Loads the earned achievements for the current logged in user.
             * @function loadAchievements
             * @memberOf Cocoon.Social.GameCenter
             * @param {function} callback The callback function. It receives the following parameters:
             * - Array of {@link Cocoon.Social.GameCenter.Achievement}.
             * - Error.
             */
            loadAchievements: function(callback) {
                Cocoon.exec(this.serviceName, "loadAchievements", [], function(achievements) {
                    callback(achievements || [], null);
                }, function(error) {
                    callback(null, error);
                });
            },

            /**
             * Loads the application achievement descriptions.
             * @function loadAchievementDescriptions
             * @memberOf Cocoon.Social.GameCenter
             * @param {function} callback The callback function. It receives the following parameters:
             * - Array of {@link Cocoon.Social.GameCenter.Achievement}.
             * - Error.
             */
            loadAchievementDescriptions: function(callback) {
                Cocoon.exec(this.serviceName, "loadAchievementDescriptions", [], function(descriptions) {
                    callback(descriptions || [], null);
                }, function(error) {
                    callback(null, error);
                });
            },

            /**
             * Load the application achievement descriptions.
             * @function loadScores
             * @memberOf Cocoon.Social.GameCenter
             * @param {function} callback The callback function. It receives the following parameters:
             * - {@link Cocoon.Social.GameCenter.Leaderboard}.
             * - Error.
             * @param {Cocoon.Social.GameCenter.Leaderboard} [query] Optional query parameters.
             */
            loadScores: function(callback, query) {
                Cocoon.exec(this.serviceName, "loadScores", [query], function(scores) {
                    callback(scores || [], null);
                }, function(error) {
                    callback(null, error);
                });
            },

            /**
             * Report user score to the server.
             * @function submitScore
             * @memberOf Cocoon.Social.GameCenter
             * @param {Cocoon.Social.GameCenter.Score} score Definition of the score and it's category (leaderboardID).
             * If no category is specified the default one is used.
             * @param {function} callback The callback function. Response params: error.
             */
            submitScore: function(score, callback) {
                Cocoon.exec(this.serviceName, "submitScore", [score], function() {
                    callback();
                }, function(error) {
                    callback(error);
                });
            },

            /**
             * Reports user earned achievements to the server.
             * @function submitAchievements
             * @memberOf Cocoon.Social.GameCenter
             * @param {array} achievements - Array of {@link Cocoon.Social.GameCenter.Achievement} objects.
             * @param {function} callback The callback function. Response params: error.
             */
            submitAchievements: function(achievements, callback) {
                Cocoon.exec(this.serviceName, "submitAchievements", [achievements], function() {
                    callback();
                }, function(error) {
                    callback(error);
                });
            },

            /**
             * Resets all the achievements of the current logged in user.
             * @function resetAchievements
             * @memberOf Cocoon.Social.GameCenter
             * @param {function} [callback] The callback function. Response params: error.
             */
            resetAchievements: function(callback) {
                Cocoon.exec(this.serviceName, "resetAchievements", [], function() {
                    callback();
                }, function(error) {
                    callback(error);
                });
            },

            /**
             * Shows a native view with the standard user interface for achievements.
             * @function showAchievements
             * @memberOf Cocoon.Social.GameCenter
             * @param {function} callback The callback function when the view is closed by the user. Response params: error
             */
            showAchievements: function(callback) {
                Cocoon.exec(this.serviceName, "showAchievements", [], function() {
                    callback();
                }, function(error) {
                    callback(error);
                });
            },

            /**
             * Shows a native view with the standard user interface for leaderboards.
             * @function showLeaderboards
             * @memberOf Cocoon.Social.GameCenter
             * @param {function} callback The callback function when the view is closed by the user. Response params: error
             * @param {Cocoon.Social.GameCenter.Leaderboard} [query] Optional parameters
             */
            showLeaderboards: function(callback, query) {
                Cocoon.exec(this.serviceName, "showLeaderboards", [query], function() {
                    callback();
                }, function(error) {
                    callback(error);
                });
            }
        };

        extension.GameCenter = new extension.GameCenterExtension();

        /**
         * The object that represents the information of a Game Center player.
         * @memberof Cocoon.Social.GameCenter
         * @name Cocoon.Social.GameCenter.Player
         * @property {object} Cocoon.Social.GameCenter.Player - The object itself
         * @property {string} Cocoon.Social.GameCenter.Player.playerID The identifier of the player.
         * @property {string} Cocoon.Social.GameCenter.Player.alias The alias of the player.
         * @property {boolean} Cocoon.Social.GameCenter.Player.isFriend True if the user is friend of the local player.
         */
        extension.GameCenter.Player = function() {

            this.playerID = "";

            this.alias = "";

            this.isFriend = false;
        };

        /**
         * The object that represents the information of a Game Center local player.
         * @memberof Cocoon.Social.GameCenter
         * @name Cocoon.Social.GameCenter.LocalPlayer
         * @property {object} Cocoon.Social.GameCenter.LocalPlayer - The object itself
         * @property {string} Cocoon.Social.GameCenter.LocalPlayer.playerID The identifier of the player.
         * @property {string} Cocoon.Social.GameCenter.LocalPlayer.alias The alias of the player.
         * @property {boolean} Cocoon.Social.GameCenter.LocalPlayer.isAuthenticated Indicates the authentication state of the current player.
         */
        extension.GameCenter.LocalPlayer = function() {

            this.playerID = "";

            this.alias = "";

            this.isAuthenticated = false;
        };

        /**
         * The object that represents an earned achievement by the user.
         * @memberof Cocoon.Social.GameCenter
         * @name Cocoon.Social.GameCenter.Achievement
         * @property {object} Cocoon.Social.GameCenter.Achievement - The object itself
         * @property {string} Cocoon.Social.GameCenter.Achievement.identifier The id of the achievement.
         * @property {number} Cocoon.Social.GameCenter.Achievement.percentComplete Percentage of achievement complete (from 0 to 100).
         * @property {number} Cocoon.Social.GameCenter.Achievement.lastReportedDate Date the achievement was last reported (unix time).
         */
        extension.GameCenter.Achievement = function(identifier, percentComplete) {

            this.identifier = identifier;

            this.percentComplete = percentComplete;

            this.lastReportedDate = 0;
        };

        /**
         * The object that represents an earned achievement by the user.
         * @memberof Cocoon.Social.GameCenter
         * @name Cocoon.Social.GameCenter.AchievementDescription
         * @property {object} Cocoon.Social.GameCenter.AchievementDescription - The object itself
         * @property {string} Cocoon.Social.GameCenter.AchievementDescription.identifier The identifier of the achievement.
         * @property {string} Cocoon.Social.GameCenter.AchievementDescription.title The title of the achievement.
         * @property {string} Cocoon.Social.GameCenter.AchievementDescription.achievedDescription The description for an achieved achievement.
         * @property {string} Cocoon.Social.GameCenter.AchievementDescription.unachievedDescription The description for an unachieved achievement.
         * @property {number} Cocoon.Social.GameCenter.AchievementDescription.maximumPoints The maximum points of the achievement.
         */
        extension.GameCenter.AchievementDescription = function() {

            this.identifier = "";

            this.title = "";

            this.achievedDescription = "";

            this.unachievedDescription = "";

            this.maximumPoints = 0;
        };

        /**
         * The object that represents a score in the leaderboards.
         * @memberof Cocoon.Social.GameCenter
         * @name Cocoon.Social.GameCenter.Score
         * @property {object} Cocoon.Social.GameCenter.Score - The object itself
         * @property {string} Cocoon.Social.GameCenter.Score.userID The identifier of the player that recorded the score.
         * @property {number} Cocoon.Social.GameCenter.Score.score The score value as a 64bit integer.
         * @property {string} Cocoon.Social.GameCenter.Score.userName The name of the user.
         * @property {string} Cocoon.Social.GameCenter.Score.imageURL imageURL The url of the user image.
         * @property {string} Cocoon.Social.GameCenter.Score.leaderboardID Leaderboard category.
         * @property {number} Cocoon.Social.GameCenter.Score.rank The rank of the player within the leaderboard.
         */
        extension.GameCenter.Score = function(userID, score, userName, imageURL, leaderboardID, originalScoreObject) {

            this.userID = userID;

            this.score = score || 0;

            this.userName = userName;

            this.imageURL = imageURL;

            this.leaderboardID = leaderboardID;

            this.rank = originalScoreObject.rank;

            this.originalScoreObject = originalScoreObject;

            return this;
        };

        /**
         * The object that represents the set of high scores for the current game.
         * @memberof Cocoon.Social.GameCenter
         * @name Cocoon.Social.GameCenter.Leaderboard
         * @property {object} Cocoon.Social.GameCenter.Leaderboard - The object itself
         * @property {string} Cocoon.Social.GameCenter.Leaderboard.category The category of the leaderboard (query parameter).
         * @property {array} Cocoon.Social.GameCenter.Leaderboard.playerIDs Player identifiers array (query parameter).
         * @property {Cocoon.Social.GameCenter.TimeScope} Cocoon.Social.GameCenter.Leaderboard.timeScope Time scope (query parameter).
         * @property {Cocoon.Social.GameCenter.PlayerScope} Cocoon.Social.GameCenter.Leaderboard.playerScope Player scope (query parameter).
         * @property {number} Cocoon.Social.GameCenter.Leaderboard.rangeStart Leaderboards start at index 1 and the length should be less than 100 (query parameter).
         * @property {number} Cocoon.Social.GameCenter.Leaderboard.rangeLength Leaderboards start at index 1 and the length should be less than 100 (query parameter).
         * @property {array} Cocoon.Social.GameCenter.Leaderboard.scores Scores array (response parameter).
         * @property {Cocoon.Social.GameCenter.Score} Cocoon.Social.GameCenter.Leaderboard.localPlayerScore Local player score (response parameter).
         * @property {string} Cocoon.Social.GameCenter.Leaderboard.localizedTitle Localized category title.
         */
        extension.GameCenter.Leaderboard = function(category, playerIDs, timeScope, playerScope, rangeStart, rangeLength) {

            this.category = category;

            this.playerIDs = playerIDs;

            this.timeScope = timeScope;

            this.playerScope = playerScope;

            this.rangeStart = rangeStart;

            this.rangeLength = rangeLength;

            this.scores = [];

            this.localPlayerScore = [];

            this.localizedTitle = localizedTitle;
        };

        /**
         * This object represents the possible Time Scopes for a leaderboard query.
         * @memberof Cocoon.Social.GameCenter
         * @name Cocoon.Social.GameCenter.TimeScope
         * @property {object} Cocoon.Social.GameCenter.TimeScope - The object itself
         * @property {string} Cocoon.Social.GameCenter.TimeScope.TODAY Today.
         * @property {string} Cocoon.Social.GameCenter.TimeScope.WEEK A week.
         * @property {string} Cocoon.Social.GameCenter.TimeScope.ALL_TIME All registered time.
         */
        extension.GameCenter.TimeScope = {
            TODAY: 0,
            WEEK: 1,
            ALL_TIME: 2
        };

        /**
         * This object represents the possible Player Scopes for a leaderboad query.
         * @memberof Cocoon.Social.GameCenter
         * @name Cocoon.Social.GameCenter.PlayerScope
         * @property {object} Cocoon.Social.GameCenter.PlayerScope - The object itself
         * @property {string} Cocoon.Social.GameCenter.PlayerScope.GLOBAL Global.
         * @property {string} Cocoon.Social.GameCenter.PlayerScope.FRIENDS Friends.
         */
        extension.GameCenter.PlayerScope = {
            GLOBAL: 0,
            FRIENDS: 1
        };

        //Social API Interface
        extension.SocialGamingServiceGameCenter = function(gcExtension) {
            Cocoon.Social.SocialGamingServiceGameCenter.superclass.constructor.call(this);
            this.gc = gcExtension;
            var me = this;
            this.gc.on("loginStatusChanged", function(localPlayer, error) {
                me.onLoginStatusChanged.emit("loginStatusChanged", [localPlayer && localPlayer.isAuthenticated, error]);
            });
        };

        extension.SocialGamingServiceGameCenter.prototype = {

            _cachedAchievements: null,

            isLoggedIn: function() {
                return this.gc.isLoggedIn();
            },
            login: function(callback) {
                this.gc.login(function(localPlayer, error) {
                    if (callback)
                        callback(localPlayer && localPlayer.isAuthenticated, error);
                });
            },
            logout: function(callback) {
                if (callback)
                    callback({
                        message: "User has to logout from the Game Center APP"
                    });
            },
            getLoggedInUser: function() {
                return fromGCPLayerToCocoonUser(this.gc._currentPlayer ? this.gc._currentPlayer : this.gc.getLocalPlayer());
            },

            requestUser: function(callback, userId) {
                if (userId) {
                    this.gc.loadPlayers([userId], function(response, error) {
                        var user = response && response.length ? fromGCPLayerToCocoonUser(response[0]) : null;
                        callback(user, error);
                    });
                } else {
                    var me = this;
                    setTimeout(function() {
                        callback(me.getLoggedInUser());
                    });
                }
            },
            requestFriends: function(callback, userId) {
                this.gc.loadFriends(function(friends, error) {
                    var users = [];
                    if (friends && friends.length) {
                        for (var i = 0; i < friends.length; ++i) {
                            users.push(fromGCPLayerToCocoonUser(friends[i]));
                        }
                    }
                    callback(users, error);
                });
            },
            requestScore: function(callback, params) {
                var query = {};
                var options = params || {};
                if (options.leaderboardID)
                    query.category = options.leaderboardID;
                query.playerIDs = [options.userID || this.getLoggedInUser().userID];

                this.gc.loadScores(function(response, error) {
                    var gcScore = null;
                    if (options.userID && response && response.scores && response.scores.length)
                        gcScore = response.scores[0];
                    else if (response && response.localPlayerScore)
                        gcScore = response.localPlayerScore;
                    var loadedScore = gcScore ? new Cocoon.Social.Score(gcScore.playerID, gcScore.value, "", "", gcScore.category, gcScore) : null;
                    callback(loadedScore, error);
                }, query);
            },
            submitScore: function(score, callback, params) {
                var options = params || {};
                this.gc.submitScore({
                    value: score,
                    category: options.leaderboardID || ""
                }, function(error) {
                    if (callback)
                        callback(error);
                });
            },
            showLeaderboard: function(callback, params) {
                var options = params || {};
                this.gc.showLeaderboards(function(error) {
                    if (callback)
                        callback(error);
                }, {
                    category: options.leaderboardID || ""
                });
            },
            //internal utility function
            prepareAchievements: function(reload, callback) {

                if (!this._cachedAchievements || reload) {
                    var me = this;
                    this.gc.loadAchievementDescriptions(function(response, error) {
                        if (error) {
                            callback([], error);
                        } else {
                            var achievements = [];
                            if (response && response.length) {
                                for (var i = 0; i < response.length; i++) {
                                    achievements.push(fromGCAchievementDescription(response[i]));
                                }
                            }
                            me.setCachedAchievements(achievements);
                            callback(achievements, null);
                        }

                    });
                } else {
                    callback(this._cachedAchievements, null);
                }
            },
            requestAllAchievements: function(callback) {
                this.prepareAchievements(true, callback);
            },
            requestAchievements: function(callback, userID) {
                var me = this;
                this.prepareAchievements(false, function(allAchievements, error) {
                    if (error) {
                        callback([], error);
                        return;
                    }
                    me.gc.loadAchievements(function(response, error) {
                        if (!error) {
                            var achievements = [];
                            if (response && response.length) {
                                for (var i = 0; i < response.length; i++) {
                                    var ach = me.findAchievement(response[i].identifier);
                                    if (ach)
                                        achievements.push(ach);
                                }
                            }
                            callback(achievements, null);
                        } else {
                            callback([], response.error);
                        }

                    });
                });
            },
            submitAchievement: function(achievementID, callback) {
                if (achievementID === null || typeof achievementID === 'undefined')
                    throw "No achievementID specified";
                var achID = this.translateAchievementID(achievementID);
                this.gc.submitAchievements([{
                    identifier: achID,
                    percentComplete: 100
                }], callback);
            },
            resetAchievements: function(callback) {
                this.gc.resetAchievements(callback);
            },
            showAchievements: function(callback) {
                this.gc.showAchievements(function(error) {
                    if (callback)
                        callback(error);
                });
            }
        };

        Cocoon.extend(extension.SocialGamingServiceGameCenter, extension.SocialGamingService);

        function fromGCPLayerToCocoonUser(player) {
            return new Cocoon.Social.User(player.playerID, player.alias);
        }

        function fromGCAchievementDescription(ach) {
            return new Cocoon.Social.Achievement(ach.identifier, ach.title, ach.achievedDescription, "", ach.maximumPoints);
        }

        return extension;
    });

})();<commit_msg>Game Center files removed<commit_after><|endoftext|>


<commit_before>// (C) Copyright 2014-2015 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';

const CLASS_ROOT = "button";

class Button extends Component {
  render () {
    var classes = [CLASS_ROOT];
    if (this.props.primary) {
      classes.push(CLASS_ROOT + "--primary");
    }
    if (this.props.secondary) {
      classes.push(CLASS_ROOT + "--secondary");
    }
    if (this.props.accent) {
      classes.push(CLASS_ROOT + "--accent");
    }
    if (! this.props.onClick) {
      classes.push(CLASS_ROOT + "--disabled");
    }
    if (this.props.fill) {
      classes.push(CLASS_ROOT + "--fill");
    }
    if (this.props.className) {
      classes.push(this.props.className);
    }

    var type = this.props.type;
    if (this.props.type === 'icon') {
      classes.push(CLASS_ROOT + "--icon");
      type = 'button';
    }

    var children = React.Children.map(this.props.children, function (child) {
      if (child && child.icon) {
        return {child};
      } else {
        return child;
      }
    });
    if (! children) {
      children = this.props.label;
    }

    return (
      <button id={this.props.id} type={type} className={classes.join(' ')}
        onClick={this.props.onClick} disabled={! this.props.onClick}>
        {children}
      </button>
    );
  }
}

Button.propTypes = {
  accent: PropTypes.bool,
  fill: PropTypes.bool,
  icon: PropTypes.bool,
  id: PropTypes.string,
  label: PropTypes.node,
  onClick: PropTypes.func,
  primary: PropTypes.bool,
  secondary: PropTypes.bool,
  type: PropTypes.oneOf(['button', 'reset', 'submit', 'icon'])
};

Button.defaultProps = {
  type: "button"
};

module.exports = Button;
<commit_msg>Added proper check for component type in Button<commit_after>// (C) Copyright 2014-2015 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';

const CLASS_ROOT = "button";

class Button extends Component {
  render () {
    var classes = [CLASS_ROOT];
    if (this.props.primary) {
      classes.push(CLASS_ROOT + "--primary");
    }
    if (this.props.secondary) {
      classes.push(CLASS_ROOT + "--secondary");
    }
    if (this.props.accent) {
      classes.push(CLASS_ROOT + "--accent");
    }
    if (! this.props.onClick) {
      classes.push(CLASS_ROOT + "--disabled");
    }
    if (this.props.fill) {
      classes.push(CLASS_ROOT + "--fill");
    }
    if (this.props.className) {
      classes.push(this.props.className);
    }

    var type = this.props.type;
    if (this.props.type === 'icon') {
      classes.push(CLASS_ROOT + "--icon");
      type = 'button';
    }

    var children = React.Children.map(this.props.children, function (child) {
      if (child && child.type.icon) {
        return {child};
      } else {
        return child;
      }
    });
    if (! children) {
      children = this.props.label;
    }

    return (
      <button id={this.props.id} type={type} className={classes.join(' ')}
        onClick={this.props.onClick} disabled={! this.props.onClick}>
        {children}
      </button>
    );
  }
}

Button.propTypes = {
  accent: PropTypes.bool,
  fill: PropTypes.bool,
  icon: PropTypes.bool,
  id: PropTypes.string,
  label: PropTypes.node,
  onClick: PropTypes.func,
  primary: PropTypes.bool,
  secondary: PropTypes.bool,
  type: PropTypes.oneOf(['button', 'reset', 'submit', 'icon'])
};

Button.defaultProps = {
  type: "button"
};

module.exports = Button;
<|endoftext|>