<commit_before>var _scrollSpeed  = 1000,
    _slider_delay = 0;

window.navHeight  = jQuery("#header").height();

jQuery("a.scrollTo").bind("click", function(e) {
	e.preventDefault();

	var href = jQuery(this).attr('href');
	if(href != '#') {
		jQuery('html,body').animate({scrollTop: jQuery(href).offset().top - window.navHeight}, _scrollSpeed, 'easeInOutExpo');
	}
});

jQuery("a.toTop").bind("click", function(e) {
	e.preventDefault();
	jQuery('html,body').animate({scrollTop: 0}, 1000, 'easeInOutExpo');
});

if(jQuery().fitVids) {
	jQuery("body").fitVids();
}

if(jQuery().owlCarousel) {
	owlCarouselInit(".owl-carousel");
}

function owlCarouselInit(divClass) {
	jQuery(divClass).each(function() {
		var t 			= jQuery(this),
			navigation 	= t.attr('data-navigation'),
			singleItem 	= t.attr('data-singleitem'),
			autoPlay 	= t.attr('data-autoplay'),
			transition 	= t.attr('data-transition'),
			items 		= t.attr('data-items'),

			navigation 	= (navigation == 'true') 	? true 		: false,
			singleItem 	= (singleItem == 'true') 	? true 		: false,
			autoPlay 	= (autoPlay == 'true') 		? true 		: false;
			transition 	= (transition == 'fade') 	? 'fade' 	: false;
			items 		= (items > 0) 			? items 	: 5;

		jQuery(t).owlCarousel({
			items: 			items,
			slideSpeed: 		300,
			paginationSpeed: 	600,
			navigation: 		navigation,
			singleItem: 		singleItem,
			autoPlay:		autoPlay,
			stopOnHover: 		true,
			autoHeight: 		false,
			transitionStyle: 	transition
		});
	});
}

if(jQuery().carouFredSel) {
	jQuery('ul.services').carouFredSel({
		auto: false,
		swipe: {
			onTouch: true,
			onMouse: false
		},
		prev: '#service-prev',
		next: '#service-next',
		responsive: true,
		width: '100%',
		height: 'variable',
		scroll: 1,
		items: {
			width: 292,
			height: 'variable',
			visible: {
				min: 1,
				max: 4
			}
		}
	});
}

jQuery('.animate_from_top').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,top:"0px"},1000);
	});
});

jQuery('.animate_from_bottom').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,bottom:"0px"},1000);
	});
});

jQuery('.animate_from_left').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,left:"0px"},1000);
	});
});

jQuery('.animate_from_right').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,right:"0px"},1000);
	});
});

jQuery('.animate_fade_in').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,right:"0px"},1000);
	});
});

if(jQuery().appear) {
	jQuery('*').each(function() {
		if(jQuery(this).attr('data-animation')) {
			var $animationName = jQuery(this).attr('data-animation');
			jQuery(this).appear(function() {
				jQuery(this).addClass('animated').addClass($animationName);
			});
		}
	});
}

if(jQuery().backstretch && jQuery("#static-logo").length > 0) {
	var background_image = jQuery("#static-logo").attr('data-background');

	if(background_image) {
		jQuery("#slider").backstretch(background_image, {speed: 150});
		jQuery("#slider").css({"background":"none"});
	}

}

if(jQuery().videoBG && jQuery('#videoBg').length > 0) {
	jQuery('#videoBg').videoBG(videoBg);
}

if(jQuery(".full-screen").length > 0) {
	_fullscreen();

	jQuery(window).resize(function() {
		_fullscreen();
	});
}
function _fullscreen() {

	var _screenHeight = jQuery(window).height();
	jQuery(".full-screen, .full-screen ul, .full-screen li").height(_screenHeight);

}

if(jQuery("#home").length > 0) {

	window.isOnTop 		= true;
	window.homeHeight 	= jQuery("#home").height() - window.navHeight;

	jQuery(window).scroll(function() {
		if(jQuery(document).scrollTop() > window.homeHeight) {
			if(window.isOnTop === true) {
				jQuery('#header').addClass('fixed');
				window.isOnTop = false;
			}
		} else {
			if(window.isOnTop === false) {
				jQuery('#header').removeClass('fixed');
				window.isOnTop = true;
			}
		}
	});

	jQuery(window).resize(function() {
		window.homeHeight = jQuery("#home").height() - window.navHeight;
	});

}

if(navigator.userAgent.indexOf("MSIE") > 0) {
	/* ie */
} else {
	jQuery("a.btn-fullscreen").show();
}

jQuery("a.btn-fullscreen").bind("click", function(e) {
	e.preventDefault();

	if (!document.fullscreenElement && /* alternative standard method */ !document.mozFullScreenElement && !document.webkitFullscreenElement) {  // current working methods

		if (document.documentElement.requestFullscreen) {
			document.documentElement.requestFullscreen();
		} else if (document.documentElement.mozRequestFullScreen) {
			document.documentElement.mozRequestFullScreen();
		} else if (document.documentElement.webkitRequestFullscreen) {
			document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
		}

	} else {

		if (document.cancelFullScreen) {
			document.cancelFullScreen();
		} else if (document.mozCancelFullScreen) {
			document.mozCancelFullScreen();
		} else if (document.webkitCancelFullScreen) {
			document.webkitCancelFullScreen();
		}

	}
});

var toggle = false;

if(jQuery().mb_YTPlayer) {

	jQuery(".player").mb_YTPlayer();
	jQuery("#home").css({"background":"none"});

	jQuery("#video-volume").bind("click", function(e) {
		e.preventDefault();

		if (!toggle) {
		 	toggle = true;
			jQuery("#video-volume").children().attr('class', 'fa fa-volume-up');
		} else {
			toggle = false;
			jQuery("#video-volume").children().attr('class', 'fa fa-volume-off');
		}

		jQuery('#YTPlayer').toggleVolume();
	});

}

jQuery.extend( jQuery.easing,{
	easeInOutExpo: function (x, t, b, c, d) {
		if (t==0) return b;
		if (t==d) return b+c;
		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
	},
});

<commit_msg>add fallback image to iphone<commit_after>var _scrollSpeed  = 1000,
    _slider_delay = 0;

window.navHeight  = jQuery("#header").height();

jQuery("a.scrollTo").bind("click", function(e) {
	e.preventDefault();

	var href = jQuery(this).attr('href');
	if(href != '#') {
		jQuery('html,body').animate({scrollTop: jQuery(href).offset().top - window.navHeight}, _scrollSpeed, 'easeInOutExpo');
	}
});

jQuery("a.toTop").bind("click", function(e) {
	e.preventDefault();
	jQuery('html,body').animate({scrollTop: 0}, 1000, 'easeInOutExpo');
});

if(jQuery().fitVids) {
	jQuery("body").fitVids();
}

if(jQuery().owlCarousel) {
	owlCarouselInit(".owl-carousel");
}

function owlCarouselInit(divClass) {
	jQuery(divClass).each(function() {
		var t 			= jQuery(this),
			navigation 	= t.attr('data-navigation'),
			singleItem 	= t.attr('data-singleitem'),
			autoPlay 	= t.attr('data-autoplay'),
			transition 	= t.attr('data-transition'),
			items 		= t.attr('data-items'),

			navigation 	= (navigation == 'true') 	? true 		: false,
			singleItem 	= (singleItem == 'true') 	? true 		: false,
			autoPlay 	= (autoPlay == 'true') 		? true 		: false;
			transition 	= (transition == 'fade') 	? 'fade' 	: false;
			items 		= (items > 0) 			? items 	: 5;

		jQuery(t).owlCarousel({
			items: 			items,
			slideSpeed: 		300,
			paginationSpeed: 	600,
			navigation: 		navigation,
			singleItem: 		singleItem,
			autoPlay:		autoPlay,
			stopOnHover: 		true,
			autoHeight: 		false,
			transitionStyle: 	transition
		});
	});
}

if(jQuery().carouFredSel) {
	jQuery('ul.services').carouFredSel({
		auto: false,
		swipe: {
			onTouch: true,
			onMouse: false
		},
		prev: '#service-prev',
		next: '#service-next',
		responsive: true,
		width: '100%',
		height: 'variable',
		scroll: 1,
		items: {
			width: 292,
			height: 'variable',
			visible: {
				min: 1,
				max: 4
			}
		}
	});
}

jQuery('.animate_from_top').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,top:"0px"},1000);
	});
});

jQuery('.animate_from_bottom').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,bottom:"0px"},1000);
	});
});

jQuery('.animate_from_left').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,left:"0px"},1000);
	});
});

jQuery('.animate_from_right').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,right:"0px"},1000);
	});
});

jQuery('.animate_fade_in').each(function () {
	jQuery(this).appear(function() {
		jQuery(this).delay(150).animate({opacity:1,right:"0px"},1000);
	});
});

if(jQuery().appear) {
	jQuery('*').each(function() {
		if(jQuery(this).attr('data-animation')) {
			var $animationName = jQuery(this).attr('data-animation');
			jQuery(this).appear(function() {
				jQuery(this).addClass('animated').addClass($animationName);
			});
		}
	});
}

if(jQuery().backstretch && jQuery("#static-logo").length > 0) {
	var background_image = jQuery("#static-logo").attr('data-background');

	if(background_image) {
		jQuery("#slider").backstretch(background_image, {speed: 150});
		jQuery("#slider").css({"background":"none"});
	}

}

if(jQuery().videoBG && jQuery('#videoBg').length > 0) {
	jQuery('#videoBg').videoBG(videoBg);
}

if(jQuery(".full-screen").length > 0) {
	_fullscreen();

	jQuery(window).resize(function() {
		_fullscreen();
	});
}
function _fullscreen() {

	var _screenHeight = jQuery(window).height();
	jQuery(".full-screen, .full-screen ul, .full-screen li").height(_screenHeight);

}

if(jQuery("#home").length > 0) {

	window.isOnTop 		= true;
	window.homeHeight 	= jQuery("#home").height() - window.navHeight;

	jQuery(window).scroll(function() {
		if(jQuery(document).scrollTop() > window.homeHeight) {
			if(window.isOnTop === true) {
				jQuery('#header').addClass('fixed');
				window.isOnTop = false;
			}
		} else {
			if(window.isOnTop === false) {
				jQuery('#header').removeClass('fixed');
				window.isOnTop = true;
			}
		}
	});

	jQuery(window).resize(function() {
		window.homeHeight = jQuery("#home").height() - window.navHeight;
	});

}

if(navigator.userAgent.indexOf("MSIE") > 0) {
	/* ie */
} else {
	jQuery("a.btn-fullscreen").show();
}

jQuery("a.btn-fullscreen").bind("click", function(e) {
	e.preventDefault();

	if (!document.fullscreenElement && /* alternative standard method */ !document.mozFullScreenElement && !document.webkitFullscreenElement) {  // current working methods

		if (document.documentElement.requestFullscreen) {
			document.documentElement.requestFullscreen();
		} else if (document.documentElement.mozRequestFullScreen) {
			document.documentElement.mozRequestFullScreen();
		} else if (document.documentElement.webkitRequestFullscreen) {
			document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
		}

	} else {

		if (document.cancelFullScreen) {
			document.cancelFullScreen();
		} else if (document.mozCancelFullScreen) {
			document.mozCancelFullScreen();
		} else if (document.webkitCancelFullScreen) {
			document.webkitCancelFullScreen();
		}

	}
});

var toggle = false;

if(jQuery().mb_YTPlayer) {

	jQuery(".player").mb_YTPlayer();
	jQuery("#home").css({"background":"none"});

	jQuery("#video-volume").bind("click", function(e) {
		e.preventDefault();

		if (!toggle) {
		 	toggle = true;
			jQuery("#video-volume").children().attr('class', 'fa fa-volume-up');
		} else {
			toggle = false;
			jQuery("#video-volume").children().attr('class', 'fa fa-volume-off');
		}

		jQuery('#YTPlayer').toggleVolume();
	});

}

jQuery.extend( jQuery.easing,{
	easeInOutExpo: function (x, t, b, c, d) {
		if (t==0) return b;
		if (t==d) return b+c;
		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
	},
});

if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) {
	$('#home').css('background-image', 'url(assets/images/preview/slider/piramid-glass.jpg)');
} else {
	$('#home').css('background-image', 'none');
}
<|endoftext|>


<commit_before>var options = require('optimist').argv;
var express = require('express');
var app = express();

app.configure(function(){
  app.set('port', options.port || process.env.PORT || 3000);
});

app.get('/', (function(){
  var started = new Date();
  return function(req,res) {
    res.send({
      started: started,
      uptime: (Date.now() - Number(started)) / 1000
    });
  }
})());

app.listen(app.get('port'), function() {
  console.log('express-app listening on http://localhost:%d', app.get('port'));
});
<commit_msg>Print the port that will be listened to<commit_after>var options = require('optimist').argv;
var express = require('express');
var app = express();

app.configure(function(){
  app.set('port', options.port || process.env.PORT || 3000);
});

app.get('/', (function(){
  var started = new Date();
  return function(req,res) {
    res.send({
      started: started,
      uptime: (Date.now() - Number(started)) / 1000
    });
  }
})());

console.log('express-app listening on http://localhost:%d', app.get('port'));
app.listen(app.get('port'));
<|endoftext|>


<commit_before>// Copyright (c) Serkan Yersen

// 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(exports){
    'use strict';

    exports.kwargs = function (func, defaults) {

        var removeComments = new RegExp('(\\/\\*[\\w\\\'\\s\\r\\n\\*]*\\*\\/)|(\\/\\/[\\w\\s\\\'][^\\n\\r]*$)|(<![\\-\\-\\s\\w\\>\\/]*>)', 'gim');
        var removeWhitespc = new RegExp('\\s+', 'gim');
        var matchSignature = new RegExp('function.*?\\((.*?)\\)', 'i');

        return function() {
            var args = Array.prototype.slice.call(arguments),
                kwargs = args[args.length - 1],
                name;

            if(defaults !== Object(defaults)){
                defaults = {};
            }

            if (kwargs === Object(kwargs)) {
                args.pop();
                var names = func.toString()
                                .replace(removeComments, '')
                                .replace(removeWhitespc, '')
                                .match(matchSignature)[1]
                                .split(',');

                for (var i = 0; i < names.length; i++) {
                    name = names[i];
                    if (name in kwargs) {
                        args[i] = kwargs[name];
                    }else if(name in defaults && args[i] === undefined){
                        args[i] = defaults[name];
                    }
                }
            }
            return func.apply(this, args);
        };
    };
})(this);
<commit_msg>Convert it to a Function extension<commit_after>// Copyright (c) Serkan Yersen

// 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(){
    'use strict';

    Function.prototype.kwargs = function (defaults) {

        var removeComments = new RegExp('(\\/\\*[\\w\\\'\\s\\r\\n\\*]*\\*\\/)|(\\/\\/[\\w\\s\\\'][^\\n\\r]*$)|(<![\\-\\-\\s\\w\\>\\/]*>)', 'gim');
        var removeWhitespc = new RegExp('\\s+', 'gim');
        var matchSignature = new RegExp('function.*?\\((.*?)\\)', 'i');
        var func = this;

        return function() {
            var args = Array.prototype.slice.call(arguments),
                kwargs = args[args.length - 1],
                name;

            if(defaults !== Object(defaults)){
                defaults = {};
            }

            if (kwargs === Object(kwargs)) {
                args.pop();
                var names = func.toString()
                                .replace(removeComments, '')
                                .replace(removeWhitespc, '')
                                .match(matchSignature)[1]
                                .split(',');

                for (var i = 0; i < names.length; i++) {
                    name = names[i];
                    if (name in kwargs) {
                        args[i] = kwargs[name];
                    }else if(name in defaults && args[i] === undefined){
                        args[i] = defaults[name];
                    }
                }
            }
            return func.apply(this, args);
        };
    };
})();
<|endoftext|>


<commit_before>/**
 * 静态资源加载器
 * 串行下载，下载统计
 */

var resourceLoader = (function (global) {

  var Util = {
    getType: function (arg) {
      return Object.prototype.toString.call(arg);
    },
    proxy: function (fn, context) {
      if (!fn) {
        return;
      }

      return function () {
        return fn.apply( context || this, arguments);
      };
    },
    forEach: function (arg, fn) {
      if (arg.forEach) {
        arg.forEach.call(arg, fn);
      } else {
        var type = this.getType(arg);
        if (type === '[object Array]') {
          for (var i = 0; i < arg.length; i++) {
            if (fn.call(arg[i], arg[i], i) === false) {
              return;
            }
          }
        } else if (type === '[object Object]') {
          for (var i in arg) {
            if (arg.hasOwnProperty(i)) {
              if (fn.call(arg[i], arg[i], i) === false) {
                return;
              }
            }
          }
        }
      }
    },
    // 仅仅是浅拷贝
    extend: function (destination, source) {
      for(var key in source) {
        if (source.hasOwnProperty(key)) {
          destination[key] = source[key];
        }
      }
      return destination;
    }
  };

  var StatusEnum = {
    ProcessStatus: {
      NOSTART: 0,
      RUNNING: 1,
      PAUSE: 2,
      COMPLETE: 3,
      ERROR: 4
    },
    ProcessCommand: {
      PAUSE: 0,
      STOP: 1,
      NONE: 2
    },
    FileStatus: {
      NOSTART: 0,
      RUNNING: 1,
      ERROR: 2,
      COMPLETE: 3
    }
  };

  var Loader = function (options) {
    this.conf = Util.extend({

    }, options);
    this.handler = {
      onComplete: null,
      onError: null
    };
    this._status = StatusEnum.FileStatus.NOSTART;
    var ua = navigator.userAgent;
    this._isIE = ua.indexOf('MSIE') >= 0;
    this._body = document.body || document.getElementsByTagName('body')[0];
  };

  Loader.prototype = {
    constructor: Loader,

    _onload: function (e) {
      this._status = StatusEnum.FileStatus.COMPLETE;
      this.runHandler(this.handler.onComplete, this._url);
    },

    _onerror: function (e) {
      this._status = StatusEnum.FileStatus.ERROR;
      this.runHandler(this.handler.onError, this._url);
    },

    status: function () {
      var arg = arguments[0];
      if (arg !== undefined) {
        this._status = arg;
      } else {
        return this._status;
      }
    },

    process: function (param) {
      this._url = param.url;
      if (!this._url) {
        return;
      }
      var object = null;
      this._status = StatusEnum.FileStatus.RUNNING;
      if (this._isIE) {
        object = new Image();
        object.src = this._url;
        object.onload = Util.proxy(this._onload, this);
        object.onerror = Util.proxy(this._onerror, this);
      } else {
        object = document.createElement('object');
        object.data = this._url;
        object.width  = 0;
        object.height = 0;
        object.onload = Util.proxy(this._onload, this);
        object.onerror = Util.proxy(this._onerror, this);
        this._body.appendChild(object);
      }
    },

    bind: function (handler, fn) {
      this.handler[handler] = fn;
      return this;
    },

    runHandler: function (handler, param) {
      if (!! handler) {
        handler(param);
      }
    }
  };

  var LoaderPool = function (options) {
    this.conf = Util.extend({
    }, options);
    this._cache = [];
    this._complete = [];
    this.handler = {
      onItemComplete: null,
      onItemStart: null,
      onItemError: null,
      onItemProcessing: null,
      onComplete: null,
      onStart: null,
      onError: null,
      onPause: null,
      onProcessing: null
    };
  };

  LoaderPool.prototype = {
    constructor: LoaderPool,

    _createLoader: function () {
      var loader = new Loader();
      return loader.bind('onComplete', Util.proxy(this._onItemComplete, this))
        .bind('onError', Util.proxy(this._onItemError, this));
    },

    _getLoader: function () {
      var ret = null;
      for (var i = 0; i < this._cache.length; i++) {
        var item = this._cache[i];
        if (item.status() !== StatusEnum.FileStatus.RUNNING) {
          ret = item;
          break;
        }
      }

      if (ret === null) {
        ret = this._createLoader();
        this._cache.push(ret);
      }

      return ret;
    },

    _onItemComplete: function (item) {
      this.runHandler(this.handler.onItemComplete, item);
      this._complete.push(item);
      this._toComplete();
      this._toContinue();
      this._toPause();
    },

    _onItemError: function () {
      this.runHandler(this.handler.onItemError, item)
        .runHandler(this.handler.onError, item);
      this._toComplete();
      this._toContinue();
      this._toPause();
    },

    _toComplete: function () {
      var isComplete = false;
      if (this._queue.length === this._complete.length) {
        for (var i = 0; i < this._queue.length; i++) {
          this._queue[i] = this._complete[i];
          isComplete = true;
        }

        if (isComplete && this._status !== StatusEnum.ProcessStatus.COMPLETE) {
          this._status = StatusEnum.ProcessStatus.COMPLETE;
          this.runHandler(this.handler.onComplete);
          return true;
        }
      }
      return false;
    },

    _toContinue: function () {
      if (this._status !== StatusEnum.ProcessStatus.COMPLETE && this._command == StatusEnum.ProcessCommand.NONE) {
        this.process({
          queue: this._queue
        });
      }
    },

    _toPause: function () {
      if (this._command === StatusEnum.ProcessCommand.PAUSE && this._status === StatusEnum.ProcessStatus.RUNNING) {
        this._status = StatusEnum.ProcessStatus.PAUSE;
        this.runHandler(this.handler.onPause);
      }
    },

    process: function (param) {
      this._queue = param.queue;
      this.runHandler(this.handler.onStart);
      if (!this._queue) {
        return;
      }
      this._command = StatusEnum.ProcessCommand.NONE;
      this._status = StatusEnum.ProcessStatus.RUNNING;

      if (this._toComplete()) {
        return;
      }

      if (this._queue.length > 0) {
        var loader = this._getLoader();
        if (loader !== null) {
          var item = this._queue.pop();
          if (!! item) {
            this.runHandler(this.handler.onItemStart, item);
            loader.process({
              url: item
            });
          }
        }
      }
    },

    pause: function () {
      this._command = StatusEnum.ProcessCommand.PAUSE;
    },

    goOn: function () {
      this.process({
        queue: this._queue
      });
    },

    bind: function (handler, fn) {
      this.handler[handler] = fn;
      return this;
    },

    runHandler: function (handler, param) {
      if (!! handler) {
        handler(param);
      }
      return this;
    }
  };

  var ResourceLoader = {
    load: function (param) {
      var deps = param.deps || null;
      if (deps === null) {
        console.warn('依赖资源列表为空，本次将不预加载任何内容！');
        return;
      }

      var loaderPool = new LoaderPool();
      loaderPool.bind('onItemComplete', function (url) {
        console.log(url + ' 加载完成!');
      }).bind('onComplete', function () {
        console.log('全部加载完成');
      });
      loaderPool.process({
        queue: deps
      });
    }
  };

  global.ResourceLoader = ResourceLoader;

})(window);
<commit_msg>update:改变一下代码结构<commit_after>/**
 * 静态资源加载器
 * 串行下载，下载统计
 */

var ResourceLoader = (function (global) {

  var Util = {
    getType: function (arg) {
      return Object.prototype.toString.call(arg);
    },
    proxy: function (fn, context) {
      if (!fn) {
        return;
      }

      return function () {
        return fn.apply( context || this, arguments);
      };
    },
    forEach: function (arg, fn) {
      if (arg.forEach) {
        arg.forEach.call(arg, fn);
      } else {
        var type = this.getType(arg);
        if (type === '[object Array]') {
          for (var i = 0; i < arg.length; i++) {
            if (fn.call(arg[i], arg[i], i) === false) {
              return;
            }
          }
        } else if (type === '[object Object]') {
          for (var i in arg) {
            if (arg.hasOwnProperty(i)) {
              if (fn.call(arg[i], arg[i], i) === false) {
                return;
              }
            }
          }
        }
      }
    },
    // 仅仅是浅拷贝
    extend: function (destination, source) {
      for(var key in source) {
        if (source.hasOwnProperty(key)) {
          destination[key] = source[key];
        }
      }
      return destination;
    }
  };

  var StatusEnum = {
    ProcessStatus: {
      NOSTART: 0,
      RUNNING: 1,
      PAUSE: 2,
      COMPLETE: 3,
      ERROR: 4
    },
    ProcessCommand: {
      PAUSE: 0,
      STOP: 1,
      NONE: 2
    },
    FileStatus: {
      NOSTART: 0,
      RUNNING: 1,
      ERROR: 2,
      COMPLETE: 3
    }
  };

  var Loader = function (options) {
    this.conf = Util.extend({

    }, options);
    this.handler = {
      onComplete: null,
      onError: null
    };
    this._status = StatusEnum.FileStatus.NOSTART;
    var ua = navigator.userAgent;
    this._isIE = ua.indexOf('MSIE') >= 0;
    this._body = document.body || document.getElementsByTagName('body')[0];
  };

  Loader.prototype = {
    constructor: Loader,

    _onload: function (e) {
      this._status = StatusEnum.FileStatus.COMPLETE;
      this.runHandler(this.handler.onComplete, this._url);
    },

    _onerror: function (e) {
      this._status = StatusEnum.FileStatus.ERROR;
      this.runHandler(this.handler.onError, this._url);
    },

    status: function () {
      var arg = arguments[0];
      if (arg !== undefined) {
        this._status = arg;
      } else {
        return this._status;
      }
    },

    process: function (param) {
      this._url = param.url;
      if (!this._url) {
        return;
      }
      var object = null;
      this._status = StatusEnum.FileStatus.RUNNING;
      if (this._isIE) {
        object = new Image();
        object.src = this._url;
        object.onload = Util.proxy(this._onload, this);
        object.onerror = Util.proxy(this._onerror, this);
      } else {
        object = document.createElement('object');
        object.data = this._url;
        object.width  = 0;
        object.height = 0;
        object.onload = Util.proxy(this._onload, this);
        object.onerror = Util.proxy(this._onerror, this);
        this._body.appendChild(object);
      }
    },

    bind: function (handler, fn) {
      this.handler[handler] = fn;
      return this;
    },

    runHandler: function (handler, param) {
      if (!! handler) {
        handler(param);
      }
    }
  };

  var LoaderPool = function (options) {
    this.conf = Util.extend({
    }, options);
    this._cache = [];
    this._complete = [];
    this.handler = {
      onItemComplete: null,
      onItemStart: null,
      onItemError: null,
      onItemProcessing: null,
      onComplete: null,
      onStart: null,
      onError: null,
      onPause: null,
      onProcessing: null
    };
  };

  LoaderPool.prototype = {
    constructor: LoaderPool,

    _createLoader: function () {
      var loader = new Loader();
      return loader.bind('onComplete', Util.proxy(this._onItemComplete, this))
        .bind('onError', Util.proxy(this._onItemError, this));
    },

    _getLoader: function () {
      var ret = null;
      for (var i = 0; i < this._cache.length; i++) {
        var item = this._cache[i];
        if (item.status() !== StatusEnum.FileStatus.RUNNING) {
          ret = item;
          break;
        }
      }

      if (ret === null) {
        ret = this._createLoader();
        this._cache.push(ret);
      }

      return ret;
    },

    _onItemComplete: function (item) {
      this.runHandler(this.handler.onItemComplete, item);
      this._complete.push(item);
      this._toComplete();
      this._toContinue();
      this._toPause();
    },

    _onItemError: function () {
      this.runHandler(this.handler.onItemError, item)
        .runHandler(this.handler.onError, item);
      this._toComplete();
      this._toContinue();
      this._toPause();
    },

    _toComplete: function () {
      var isComplete = false;
      if (this._queue.length === this._complete.length) {
        for (var i = 0; i < this._queue.length; i++) {
          this._queue[i] = this._complete[i];
          isComplete = true;
        }

        if (isComplete && this._status !== StatusEnum.ProcessStatus.COMPLETE) {
          this._status = StatusEnum.ProcessStatus.COMPLETE;
          this.runHandler(this.handler.onComplete);
          return true;
        }
      }
      return false;
    },

    _toContinue: function () {
      if (this._status !== StatusEnum.ProcessStatus.COMPLETE && this._command == StatusEnum.ProcessCommand.NONE) {
        this.process({
          queue: this._queue
        });
      }
    },

    _toPause: function () {
      if (this._command === StatusEnum.ProcessCommand.PAUSE && this._status === StatusEnum.ProcessStatus.RUNNING) {
        this._status = StatusEnum.ProcessStatus.PAUSE;
        this.runHandler(this.handler.onPause);
      }
    },

    process: function (param) {
      this._queue = param.queue;
      this.runHandler(this.handler.onStart);
      if (!this._queue) {
        return;
      }
      this._command = StatusEnum.ProcessCommand.NONE;
      this._status = StatusEnum.ProcessStatus.RUNNING;

      if (this._toComplete()) {
        return;
      }

      if (this._queue.length > 0) {
        var loader = this._getLoader();
        if (loader !== null) {
          var item = this._queue.pop();
          if (!! item) {
            this.runHandler(this.handler.onItemStart, item);
            loader.process({
              url: item
            });
          }
        }
      }
    },

    pause: function () {
      this._command = StatusEnum.ProcessCommand.PAUSE;
    },

    goOn: function () {
      this.process({
        queue: this._queue
      });
    },

    bind: function (handler, fn) {
      this.handler[handler] = fn;
      return this;
    },

    runHandler: function (handler, param) {
      if (!! handler) {
        handler(param);
      }
      return this;
    }
  };

  var _ResourceLoader = {
    load: function (param) {
      var deps = param.deps || null;
      if (deps === null) {
        console.warn('依赖资源列表为空，本次将不预加载任何内容！');
        return;
      }

      var loaderPool = new LoaderPool();
      loaderPool.bind('onItemComplete', function (url) {
        console.log(url + ' 加载完成!');
      }).bind('onComplete', function () {
        console.log('全部加载完成');
      });
      loaderPool.process({
        queue: deps
      });
    }
  };

  return _ResourceLoader;

})(window);
<|endoftext|>


<commit_before>/*jshint multistr: true*/
/*jslint es5: true */

(function (window, $, undefined) {
    'use strict';

    var Arduinofirmwareupload;

    Arduinofirmwareupload = function Arduinofirmwareupload(cockpit) {
        console.log("Loading Arduinofirmwareupload plugin in the browser.");

        // Instance variables
        this.cockpit = cockpit;
	this.arduinoFirmwareVM = new ArduinoFirmwareViewModel();

        // Add required UI elements
	$("#settings H4:contains('Runtime Settings:')").append(
          '
 \

Upload firmware
 \

 \
              Arduino firmware: \
               \
                 \
               \

 \
                <button type="button" class="close" data-dismiss="alert">x</button> \
                Oh snap! Only .zip, .tar.gz and .ino files are supported! \

 \

 \
                <button type="button" class="close" data-dismiss="alert">x</button> \
                Oh snap! Your browser doesn\'t support the file upload API! \

 \
\
              <button href="#firmware-upload-dialog" class="btn btn-small" type="button" id="arduinoFirmware-upload" data-bind="css: { \'btn-success\': isValidFirmwareFile() == false,  \'btn-success\': isValidFirmwareFile() }" data-toggle="modal"> \
	       Upload firmware from SD card to Arduino</button> \

');
	$("#settings").after('

');
	$("#settings").after('
 \
			              \

 \

Upload Arduino Firmware
 \

 \

 \
            Filename:  \

 \

 \

 \

Overall progress:
 \

 \

 \

 \

 \

 \

File upload:
 \

 \

 \

 \

 \

Unpacking  \

 \

Compiling  \

Upload to Arduino  \

 \

 \

 \
              Show details \

 \
                <textarea id="arduiniFirmware-details" readonly="readonly" data-bind="text: details"></textarea> \

 \

 \

 \

 \
            Cancel \
            Apply new firmware \
            Close \

 \

');

	ko.applyBindings(this.arduinoFirmwareVM);

	    var self=this;
            /* ------------------------------------------
               firmware upload
            */
            var selectedFile;
            var fileReader = new FileReader();
            $('#arduinoFirmware').live('change', function(evnt){
              selectedFile = evnt.target.files[0];
              self.selectedFile(selectedFile);
            });
            $("#arduinoFirmware-startupload").click(function() {
              fileReader.onload = function(evnt) {
                console.log("Upload event: " + selectedFile.name)
                self.cockpit.socket.emit('arduinofirmware-upload', { 'filename' : selectedFile.name, data : evnt.target.result });
              }
              if (!selectedFile) {
                selectedFile = new Object();
                selectedFile.name = 'fromSource';
                self.cockpit.socket.emit('arduinofirmware-uploadfromsource');
              }
              console.log("Starting upload: " + selectedFile.name)
              self.cockpit.socket.emit('arduinofirmware-startupload', { 'filename' : selectedFile.name, 'size' : selectedFile.size });
	      selectedFile = null;
            });
            $('#arduinoFirmware-closeupload').click(function() {
              self.arduinoFirmwareVM.reset();
              //$('#firmware-upload-dialog').modal('hide');
            });
            $('#arduinoFirmware-showdetails').click(function() {
              self.arduinoFirmwareVM.toggleDetails();
            });

            this.arduinoFirmwareVM.details.subscribe(function(data) {
              $('#arduiniFirmware-details').scrollTop($('#arduiniFirmware-details')[0].scrollHeight);
            });

        // Register the various event handlers
        this.listen();

    };

    //This pattern will hook events in the cockpit and pull them all back
    //so that the reference to this instance is available for further processing
    Arduinofirmwareupload.prototype.listen = function listen() {
        var arduinofirmware = this;
        $("#diagnostic .back-button").click(function (){
            arduinofirmware.SaveSettings();
        });
        this.cockpit.socket.on('settings', function(data) {
            arduinofirmware.LoadSettings(data);
        });
	this.cockpit.socket.on('arduinofirmware-requestmoredata', function (data){
	   arduinofirmware.arduinoFirmwareVM.uploadPercentage(data['Percent']);
	   var Place = data['Place'] * 524288; //The Next Blocks Starting Position
	   var NewFile; //The Variable that will hold the new Block of Data
	   if (selectedFile.slice != undefined)
	   {
	     NewFile = selectedFile.slice(Place, Place + Math.min(524288, (selectedFile.size-Place)));
	   }
	   else if (selectedFile.webkitSlice != undefined)
	   {
	     NewFile = selectedFile.webkitSlice(Place, Place + Math.min(524288, (selectedFile.size-Place)));
	   }
	   fileReader.readAsBinaryString(NewFile);
	});

	this.cockpit.socket.on('arduinofirmware-uploaddone', function(data){
	  arduinofirmware.arduinoFirmwareVM.uploaded(true);
	  arduinofirmware.arduinoFirmwareVM.uploadPercentage(100);
	});

	this.cockpit.socket.on('arduinoFirmware-status', function(data){
	  arduinofirmware.arduinoFirmwareVM.updateStatus(data);
	});

	this.cockpit.socket.on('arduinoFirmware-output', function(data){
	  arduinofirmware.arduinoFirmwareVM.logOutput(data);
	});
    };

    Arduinofirmwareupload.prototype.LoadSettings = function LoadSettings(settings){
    };

    Arduinofirmwareupload.prototype.SaveSettings = function SaveSettings(){
    };

    window.Cockpit.plugins.push(Arduinofirmwareupload);

}(window, jQuery));

function ArduinoFirmwareViewModel(){
    var self = this;
    var numberOfSteps = 6;

    self.stepsDone = ko.observable(0);

    self.selectedFile = ko.observable();

    self.uploadPercentage = ko.observable(0);

    self.uploaded = ko.observable(false);
    self.unpacking = ko.observable(false);
    self.unpacked = ko.observable(false);
    self.compiling = ko.observable(false);
    self.compiled = ko.observable(false);
    self.arduinoUploading = ko.observable(false);
    self.arduinoUploaded = ko.observable(false);
    self.detailsVisible = ko.observable(false);
    self.details = ko.observable();
    self.failed = ko.observable(false);

    self.reset = function() {
        self.stepsDone(0);
        self.selectedFile('');
        self.uploadPercentage(0);
        self.uploaded(false);
        self.unpacked(false)
        self.unpacking(false);
        self.compiling(false);
        self.compiled(false);
        self.arduinoUploading(false);
        self.arduinoUploaded(false);
        self.detailsVisible(false);
        self.details('');
	self.failed(false);
    };

    self.selectedFileName = ko.computed(function() {
        if (self.selectedFile()){
            return self.selectedFile().name;
        }
        return "";
    });

    self.isValidFirmwareFile = ko.computed(function() {
        var fileName = self.selectedFileName();
        var ext = fileName.split('.').pop().toLowerCase();
        return ($.inArray(ext, ['zip', 'ino' , 'gz']) != -1);
    });

    self.browserDoesSupportFileApi = ko.computed(function() {
        return !(window.File && window.FileReader);
    });

    self.overallPercentage = ko.computed(function() {
        var percentage =  (100/numberOfSteps) * self.stepsDone();
        console.log("percentage: " + numberOfSteps + " done: " + self.stepsDone());
        return percentage;
    });

    self.inProgress = ko.computed(function() {
        return self.stepsDone() != 0;
    });

    self.updateStatus = function(data){
        if (data.errorMessage){
            self.failed(true);
            return;
        }
        if (self[self.lastStatus]) {
            self[self.lastStatus](false);
        }
        self[data.key](true);
        self.stepsDone(self.stepsDone() + 1);
    };

    self.toggleDetails = function(){
        if (self.detailsVisible()) {
            self.detailsVisible(false);
        }
        else {
            self.detailsVisible(true);
        }
    };

    self.logOutput = function(data) {
        self.details(self.details() + data);
    }

}

<commit_msg>Fixed high cpu by disabling bootstrap css progress bar animation<commit_after>/*jshint multistr: true*/
/*jslint es5: true */

(function (window, $, undefined) {
    'use strict';

    var Arduinofirmwareupload;

    Arduinofirmwareupload = function Arduinofirmwareupload(cockpit) {
        console.log("Loading Arduinofirmwareupload plugin in the browser.");

        // Instance variables
        this.cockpit = cockpit;
	this.arduinoFirmwareVM = new ArduinoFirmwareViewModel();

        // Add required UI elements
	$("#settings H4:contains('Runtime Settings:')").append(
          '
 \

Upload firmware
 \

 \
              Arduino firmware: \
               \
                 \
               \

 \
                <button type="button" class="close" data-dismiss="alert">x</button> \
                Oh snap! Only .zip, .tar.gz and .ino files are supported! \

 \

 \
                <button type="button" class="close" data-dismiss="alert">x</button> \
                Oh snap! Your browser doesn\'t support the file upload API! \

 \
\
              <button href="#firmware-upload-dialog" class="btn btn-small" type="button" id="arduinoFirmware-upload" data-bind="css: { \'btn-success\': isValidFirmwareFile() == false,  \'btn-success\': isValidFirmwareFile() }" data-toggle="modal"> \
	       Upload firmware from SD card to Arduino</button> \

');
	$("#settings").after('

');
	$("#settings").after('
 \
			              \

 \

Upload Arduino Firmware
 \

 \

 \
            Filename:  \

 \

 \

 \

Overall progress:
 \

 \

 \

 \

 \

 \

File upload:
 \

 \

 \

 \

 \

Unpacking  \

 \

Compiling  \

Upload to Arduino  \

 \

 \

 \
              Show details \

 \
                <textarea id="arduiniFirmware-details" readonly="readonly" data-bind="text: details"></textarea> \

 \

 \

 \

 \
            Cancel \
            Apply new firmware \
            Close \

 \

');

	ko.applyBindings(this.arduinoFirmwareVM);

	    var self=this;
            /* ------------------------------------------
               firmware upload
            */
            var selectedFile;
            var fileReader = new FileReader();
            $('#arduinoFirmware').live('change', function(evnt){
              selectedFile = evnt.target.files[0];
              self.selectedFile(selectedFile);
            });
            $("#arduinoFirmware-startupload").click(function() {
              fileReader.onload = function(evnt) {
                console.log("Upload event: " + selectedFile.name)
                self.cockpit.socket.emit('arduinofirmware-upload', { 'filename' : selectedFile.name, data : evnt.target.result });
              }
              if (!selectedFile) {
                selectedFile = new Object();
                selectedFile.name = 'fromSource';
                self.cockpit.socket.emit('arduinofirmware-uploadfromsource');
              }
              console.log("Starting upload: " + selectedFile.name)
              self.cockpit.socket.emit('arduinofirmware-startupload', { 'filename' : selectedFile.name, 'size' : selectedFile.size });
	      selectedFile = null;
            });
            $('#arduinoFirmware-closeupload').click(function() {
              self.arduinoFirmwareVM.reset();
              //$('#firmware-upload-dialog').modal('hide');
            });
            $('#arduinoFirmware-showdetails').click(function() {
              self.arduinoFirmwareVM.toggleDetails();
            });

            this.arduinoFirmwareVM.details.subscribe(function(data) {
              $('#arduiniFirmware-details').scrollTop($('#arduiniFirmware-details')[0].scrollHeight);
            });

        // Register the various event handlers
        this.listen();

    };

    //This pattern will hook events in the cockpit and pull them all back
    //so that the reference to this instance is available for further processing
    Arduinofirmwareupload.prototype.listen = function listen() {
        var arduinofirmware = this;
        $("#diagnostic .back-button").click(function (){
            arduinofirmware.SaveSettings();
        });
        this.cockpit.socket.on('settings', function(data) {
            arduinofirmware.LoadSettings(data);
        });
	this.cockpit.socket.on('arduinofirmware-requestmoredata', function (data){
	   arduinofirmware.arduinoFirmwareVM.uploadPercentage(data['Percent']);
	   var Place = data['Place'] * 524288; //The Next Blocks Starting Position
	   var NewFile; //The Variable that will hold the new Block of Data
	   if (selectedFile.slice != undefined)
	   {
	     NewFile = selectedFile.slice(Place, Place + Math.min(524288, (selectedFile.size-Place)));
	   }
	   else if (selectedFile.webkitSlice != undefined)
	   {
	     NewFile = selectedFile.webkitSlice(Place, Place + Math.min(524288, (selectedFile.size-Place)));
	   }
	   fileReader.readAsBinaryString(NewFile);
	});

	this.cockpit.socket.on('arduinofirmware-uploaddone', function(data){
	  arduinofirmware.arduinoFirmwareVM.uploaded(true);
	  arduinofirmware.arduinoFirmwareVM.uploadPercentage(100);
	});

	this.cockpit.socket.on('arduinoFirmware-status', function(data){
	  arduinofirmware.arduinoFirmwareVM.updateStatus(data);
	});

	this.cockpit.socket.on('arduinoFirmware-output', function(data){
	  arduinofirmware.arduinoFirmwareVM.logOutput(data);
	});
    };

    Arduinofirmwareupload.prototype.LoadSettings = function LoadSettings(settings){
    };

    Arduinofirmwareupload.prototype.SaveSettings = function SaveSettings(){
    };

    window.Cockpit.plugins.push(Arduinofirmwareupload);

}(window, jQuery));

function ArduinoFirmwareViewModel(){
    var self = this;
    var numberOfSteps = 6;

    self.stepsDone = ko.observable(0);

    self.selectedFile = ko.observable();

    self.uploadPercentage = ko.observable(0);

    self.uploaded = ko.observable(false);
    self.unpacking = ko.observable(false);
    self.unpacked = ko.observable(false);
    self.compiling = ko.observable(false);
    self.compiled = ko.observable(false);
    self.arduinoUploading = ko.observable(false);
    self.arduinoUploaded = ko.observable(false);
    self.detailsVisible = ko.observable(false);
    self.details = ko.observable();
    self.failed = ko.observable(false);

    self.reset = function() {
        self.stepsDone(0);
        self.selectedFile('');
        self.uploadPercentage(0);
        self.uploaded(false);
        self.unpacked(false)
        self.unpacking(false);
        self.compiling(false);
        self.compiled(false);
        self.arduinoUploading(false);
        self.arduinoUploaded(false);
        self.detailsVisible(false);
        self.details('');
	self.failed(false);
    };

    self.selectedFileName = ko.computed(function() {
        if (self.selectedFile()){
            return self.selectedFile().name;
        }
        return "";
    });

    self.isValidFirmwareFile = ko.computed(function() {
        var fileName = self.selectedFileName();
        var ext = fileName.split('.').pop().toLowerCase();
        return ($.inArray(ext, ['zip', 'ino' , 'gz']) != -1);
    });

    self.browserDoesSupportFileApi = ko.computed(function() {
        return !(window.File && window.FileReader);
    });

    self.overallPercentage = ko.computed(function() {
        var percentage =  (100/numberOfSteps) * self.stepsDone();
        console.log("percentage: " + numberOfSteps + " done: " + self.stepsDone());
        return percentage;
    });

    self.inProgress = ko.computed(function() {
        return self.stepsDone() != 0;
    });

    self.updateStatus = function(data){
        if (data.errorMessage){
            self.failed(true);
            return;
        }
        if (self[self.lastStatus]) {
            self[self.lastStatus](false);
        }
        self[data.key](true);
        self.stepsDone(self.stepsDone() + 1);
    };

    self.toggleDetails = function(){
        if (self.detailsVisible()) {
            self.detailsVisible(false);
        }
        else {
            self.detailsVisible(true);
        }
    };

    self.logOutput = function(data) {
        self.details(self.details() + data);
    }

}

<|endoftext|>


<commit_before>/*
	Page elements
 */

/*
	States and animating variables
*/

var Universe = {
	systems : null,
	x : 0,
	y : 0,
	touchxstart: 0,
	touchxcurrent: 0,
	touchxend: 0,
	canScroll : false,

	$self : null,
	$systems : null,
	$currentsystem : null,

	init : function() {
		this.$self = $('#universe');
		this.$systems = $('#universe > .systems')
		this.$currentsystem = $('#loading')

		World.init();
		this.reset();
	},

	reset: function() {
		this.x = 0;
		this.y = 0;

		this.touchxstart = 0;
		this.touchxcurrent = 0;
		this.touchxend = 0;

		this.resize();

		resetSystems();
	},

	resize : function() {
		// resize all systems
		resizeSystems();

		// resize timeline (scrollbar)
		World.resizeTimeline();

		// move viewport immediately after resize if
		if (preload == 100) {
			this.moveViewport(0);
		}
	},

	_moveViewportTo: function(x, y, duration, callback) {
		this.$self.animate({
			'left' : x + 'px',
			'top' : y + 'px',
		}, duration, 'easeInOutQuint', function() {
			// done moving to target system
			Universe.x = x;
			Universe.y = y;

			if (callback) {
				callback();
			}
		});
	},

	moveViewport : function($system, duration, callback) {
		if ($system == undefined || typeof $system == 'function') {
			$system = Universe.$currentsystem;
		}

		this._moveViewportTo(-$system.position().left, -$system.position().top, duration, function() {
			// done moving to target system
			Universe.$currentsystem = $system;

			if (callback) {
				callback();
			}
		});
	},

	lockScroll : function() {
		this.canScroll = false;
	}
};

var World = {
	$self : null,
	$layers : null,
	$levels : null,

	init : function() {
		this.$self = $('#world');
		this.$layers = $('#world .layer');
		this.$levels = $('#world .layer.stage .level');

		this.resizeTimeline();
	},

	resizeTimeline : function() {
		var totalLength = 0;

		World.$levels.each(function(index) {
			var $level = $(this);
			if ($level.data('lvltype') == 'horizontal') {
				totalLength += $level.width();
			}
			else if ($level.data('lvltype') == 'vertical') {
				totalLength += $level.height();
			}
			else {
				// implement more chapters types here...
			}
		});

		$('#timeline').css('height', totalLength);
	},

};

var Blog = {};

var Splash = {}

var End = {};

/*
 * Utilities
 */

function getViewportSize() {
	return {
		width : $(window).width(),
		height : $(window).height()
	};
}

function applySize(element, size) {
	$(element).css({
		'width' : size.width + 'px',
		'height' : size.height + 'px',
	});
}

function changeSubsystem(element, css) {
	// save original state of element to be able to restore it?
}

/*
 * Systems (slides) management
 */

function resetSystems() {
	// reset and resize all systems and content to fit screen
	$systems.each(function(index) {
		var $system = $(this);
		var size = getViewportSize();

		resetSystem($system);
		resizeSystem($system, size);
	});

	//
}

function resizeSystems() {
	$systems.each(function(index) {
		var $system = $(this);
		var size = getViewportSize();

		resizeSystem($system, size);
	})
}

function resetSystem($system) {
	// reposition every children to original position,
}

function resizeSystem($system, size) {
	// reposition system div
	$system.css({
		'left' : ($system.data('ux') * size.width) + 'px',
		'top' : ($system.data('uy') * size.height) + 'px',
	});

	// resize system div
	applySize($system, size)
}

/*
	Animating
*/

function sfx($element, classes) {
	if ($element.hasClass('idle')) $element.removeClass('idle');
	$element.addClass('animated '+ classes);
}

/*
	Preloading
*/

var preload = 0;
var preloadSI = -1;

function preloadEverything() {
	preloadElements();
	preloadSubscribe();
	preloadWorld();
	preloadPosts();

	preloadSI = setInterval(function(){
		preload += 4;
		if (preload >= 100) {
			preload = 100;
			clearInterval(preloadSI);

			Universe.moveViewport($('#site-subscribe'), 1000, function(){
				// done loading

				// animate scene
				sfx($('#site-subscribe > *'), 'bounceInLeft');
			});
		}
		$('#percent').text(preload)
	}, 100);
}

function preloadElements() {
	// cache all jQuery objects for quick access
	$loader = $('#loading');
	$universe = $('#universe'); // full-screen zones
	$systems = $('#universe > .system'); // full-screen zones
}

function preloadSubscribe() {
	// load graphics, completion-dictionnary
}

function preloadWorld() {
	// load graphics, musics, summaries
}

function preloadPosts() {
	// load posts?
}

/*
	Document initializing
*/

$(document).ready(function() {
	// cache assets and save page elements refs
	preloadEverything()

	if (deviceName != "computer") {
		alert('mobile mode')
		//initTouchEvents();
	}

	// initialize everything on the page
	Universe.init();
	Universe.lockScroll();

	$(window).on('beforeunload', function() {
		// prevent reload scroll issue
		$(window).scrollTop(0);

	}).on('scroll', function() {
		// animate on scroll
		if (Universe.canScroll) {
			animateOnScroll();
		}

	}).on('resize', function() {
		// resize world, universe and scroll length

		resizeSystems();
		World.resizeTimeline();
		animateOnScroll();

	}).on('orientationchange', function(event) {
		// freeze world during orientation changes

		Universe.lockScroll();
		setTimeout(function() {
			$(window).trigger('resize');
		}, 500);

	});

	$('#btViewSite').click(function(){
		Universe.moveViewport($('#site-wait'), 1000, function(){
			// display hints how to use the world...

			// auto switch to world after small 4s delay
			setTimeout(function(){
				Universe.moveViewport($('#site-world'), 500, function(){
					//
				});
			},4000);
		})
	});
});

function initTouchEvents() {
	document.addEventListener("touchstart", function(e) {
		Universe.touchxstart = e.targetTouches[0].pageX;

	}, false);
	document.addEventListener("touchmove", function(e) {
		e.preventDefault();
		Universe.touchxcurrent = e.targetTouches[0].pageX;

		if (Universe.canScroll) {
			animateOnScroll();
		}

	}, false);
	document.addEventListener("touchend", function(e) {
		e.preventDefault();
		Universe.touchxend = e.changedTouches[0].pageX;

	}, false);
}

function animateOnScroll() {
	//
}
<commit_msg>added function to animate/reset elements using css animations<commit_after>/*
	Page elements
 */

/*
	States and animating variables
*/

var Universe = {
	systems : null,
	x : 0,
	y : 0,
	touchxstart: 0,
	touchxcurrent: 0,
	touchxend: 0,
	canScroll : false,

	$self : null,
	$systems : null,
	$currentsystem : null,

	init : function() {
		this.$self = $('#universe');
		this.$systems = $('#universe > .systems')
		this.$currentsystem = $('#loading')

		World.init();
		this.reset();
	},

	reset: function() {
		this.x = 0;
		this.y = 0;

		this.touchxstart = 0;
		this.touchxcurrent = 0;
		this.touchxend = 0;

		this.resize();

		resetSystems();
	},

	resize : function() {
		// resize all systems
		resizeSystems();

		// resize timeline (scrollbar)
		World.resizeTimeline();

		// move viewport immediately after resize if
		if (preload == 100) {
			this.moveViewport(0);
		}
	},

	_moveViewportTo: function(x, y, duration, callback) {
		this.$self.animate({
			'left' : x + 'px',
			'top' : y + 'px',
		}, duration, 'easeInOutQuint', function() {
			// done moving to target system
			Universe.x = x;
			Universe.y = y;

			if (callback) {
				callback();
			}
		});
	},

	moveViewport : function($system, duration, callback) {
		if ($system == undefined || typeof $system == 'function') {
			$system = Universe.$currentsystem;
		}

		this._moveViewportTo(-$system.position().left, -$system.position().top, duration, function() {
			// done moving to target system
			Universe.$currentsystem = $system;

			if (callback) {
				callback();
			}
		});
	},

	lockScroll : function() {
		this.canScroll = false;
	}
};

var World = {
	$self : null,
	$layers : null,
	$levels : null,

	init : function() {
		this.$self = $('#world');
		this.$layers = $('#world .layer');
		this.$levels = $('#world .layer.stage .level');

		this.resizeTimeline();
	},

	resizeTimeline : function() {
		var totalLength = 0;

		World.$levels.each(function(index) {
			var $level = $(this);
			if ($level.data('lvltype') == 'horizontal') {
				totalLength += $level.width();
			}
			else if ($level.data('lvltype') == 'vertical') {
				totalLength += $level.height();
			}
			else {
				// implement more chapters types here...
			}
		});

		$('#timeline').css('height', totalLength);
	},

};

var Blog = {};

var Splash = {}

var End = {};

/*
 * Utilities
 */

function getViewportSize() {
	return {
		width : $(window).width(),
		height : $(window).height()
	};
}

function applySize(element, size) {
	$(element).css({
		'width' : size.width + 'px',
		'height' : size.height + 'px',
	});
}

function changeSubsystem(element, css) {
	// save original state of element to be able to restore it?
}

/*
 * Systems (slides) management
 */

function resetSystems() {
	// reset and resize all systems and content to fit screen
	$systems.each(function(index) {
		var $system = $(this);
		var size = getViewportSize();

		resetSystem($system);
		resizeSystem($system, size);
	});

	//
}

function resizeSystems() {
	$systems.each(function(index) {
		var $system = $(this);
		var size = getViewportSize();

		resizeSystem($system, size);
	})
}

function resetSystem($system) {
	// reposition every children to original position,
}

function resizeSystem($system, size) {
	// reposition system div
	$system.css({
		'left' : ($system.data('ux') * size.width) + 'px',
		'top' : ($system.data('uy') * size.height) + 'px',
	});

	// resize system div
	applySize($system, size)
}

/*
	Animating
*/

function sfx($element, classes) {
	if ($element.hasClass('idle')) $element.removeClass('idle').addClass('nidle');
	$element.addClass('animated '+ classes);
}

function unsfx($element) {
	if ($element.hasClass('nidle')) $element.removeClass('nidle').removeClass('animated').addClass('idle');
}

/*
	Preloading
*/

var preload = 0;
var preloadSI = -1;

function preloadEverything() {
	preloadElements();
	preloadSubscribe();
	preloadWorld();
	preloadPosts();

	preloadSI = setInterval(function(){
		preload += 4;
		if (preload >= 100) {
			preload = 100;
			clearInterval(preloadSI);

			Universe.moveViewport($('#site-subscribe'), 1000, function(){
				// done loading

				// animate scene
				sfx($('#site-subscribe > *'), 'bounceInLeft');
			});
		}
		$('#percent').text(preload)
	}, 100);
}

function preloadElements() {
	// cache all jQuery objects for quick access
	$loader = $('#loading');
	$universe = $('#universe'); // full-screen zones
	$systems = $('#universe > .system'); // full-screen zones
}

function preloadSubscribe() {
	// load graphics, completion-dictionnary
}

function preloadWorld() {
	// load graphics, musics, summaries
}

function preloadPosts() {
	// load posts?
}

/*
	Document initializing
*/

$(document).ready(function() {
	// cache assets and save page elements refs
	preloadEverything()

	if (deviceName != "computer") {
		alert('mobile mode')
		//initTouchEvents();
	}

	// initialize everything on the page
	Universe.init();
	Universe.lockScroll();

	$(window).on('beforeunload', function() {
		// prevent reload scroll issue
		$(window).scrollTop(0);

	}).on('scroll', function() {
		// animate on scroll
		if (Universe.canScroll) {
			animateOnScroll();
		}

	}).on('resize', function() {
		// resize world, universe and scroll length

		resizeSystems();
		World.resizeTimeline();
		animateOnScroll();

	}).on('orientationchange', function(event) {
		// freeze world during orientation changes

		Universe.lockScroll();
		setTimeout(function() {
			$(window).trigger('resize');
		}, 500);

	});

	$('#btViewSite').click(function(){
		Universe.moveViewport($('#site-wait'), 1000, function(){
			// display hints how to use the world...

			// auto switch to world after small 4s delay
			setTimeout(function(){
				Universe.moveViewport($('#site-world'), 500, function(){
					//
				});
			},4000);
		})
	});
});

function initTouchEvents() {
	document.addEventListener("touchstart", function(e) {
		Universe.touchxstart = e.targetTouches[0].pageX;

	}, false);
	document.addEventListener("touchmove", function(e) {
		e.preventDefault();
		Universe.touchxcurrent = e.targetTouches[0].pageX;

		if (Universe.canScroll) {
			animateOnScroll();
		}

	}, false);
	document.addEventListener("touchend", function(e) {
		e.preventDefault();
		Universe.touchxend = e.changedTouches[0].pageX;

	}, false);
}

function animateOnScroll() {
	//
}
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2013 Orbeon, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */

(function() {

    var Controls = ORBEON.xforms.Controls;

    /**
     * We're asked to show the help popover for a control, either because the user clicked on the help icon,
     * or because the server asks us to do so.
     *
     * [1] We want the arrow to point to the form field, not somewhere between the label and the field,
     *     hence here we look for the first element which is not an LHHA. If we don't find any such element
     *     we use the container as a fallback (e.g. xf:group that only contains the help and a label).
     * [2] Using animation unnecessarily complicates things, by creating cases where we have two popovers
     *     in the DOM, when one is being hidden while the other is being shown, so we just disable animations.
     */
    Controls.showHelp = function(controlEl) {

        controlEl = $(controlEl);
        var labelText           = $(Controls.getControlLHHA(controlEl, 'label')).text();
        var helpText            = $(Controls.getControlLHHA(controlEl, 'help' )).text();
        var LhhaClasses         = '.xforms-label, .xforms-help, .xforms-hint, .xforms-alert';
        var firstNonLhhaChild   = controlEl.children().not(LhhaClasses).first();
        var el                  = firstNonLhhaChild.is('*') ? firstNonLhhaChild : controlEl; // [1]
        var elPos               = getPosition(el);
        var placement           = getPlacement(elPos);
        var popoverAlreadyShown = controlEl.next().is('.xforms-help-popover');

        // Hide other help popovers before (maybe) showing this one
        hideAllHelpPopovers();

        // We take users asking to show the popover when already shown as an order to hide it
        if (! popoverAlreadyShown) {

            // For top placement, popover must be above the label
            if (placement == 'top') {
                el = controlEl;
                elPos = getPosition(el);
            }

            controlEl.popover({
                placement: placement,
                trigger:   'manual',
                title:     labelText,
                content:   helpText,
                html:      true,
                animation: false // [2]
            }).popover('show');

            // Decorate an position popover
            var popover = $(controlEl).next();
            popover.addClass('xforms-help-popover');
            addClose(controlEl, popover);
            positionPopover(popover, placement, elPos);
        }
    };

    function hideAllHelpPopovers() {
        _.each($('form.xforms-form .xforms-help-popover'), function(popover) {
            $(popover).prev().popover('destroy');
        });
    }

    /**
     * Get offset/width/height of element, dealing with case where element is inline
     */
    function getPosition(el) {
        function getElPosition() {
            return {
                offset:    el.offset(),
                width :    el.outerWidth(),
                height:    el.outerHeight(),
                scrollTop: $(document).scrollTop() // Will this work if we're in a scrollable area?
            }
        }

        var pos;
        if (el.is(':hidden')) {
            var originalStyle = el.attr('style');
            el.css('display', 'inline-block');
            pos = getElPosition();
            (_.isUndefined(originalStyle))
                ? el.removeAttr('style')
                : el.attr('style', originalStyle);
        } else {
            pos = getElPosition();
        }

        var overflowEl = $(_.find($(el).parents(), function(e) { return $(e).css('overflow') == 'auto'; }));
        var overflowPos = {};
        pos.margins = ! overflowEl.is('*')
            ? { top: 0, right: 0, bottom: 0, left: 0 }
            : (
                overflowPos.offset = overflowEl.offset(),
                overflowPos.width  = overflowEl.outerWidth(),
                overflowPos.height = overflowEl.outerHeight(),
                {
                    top:    overflowPos.offset.top,
                    right:  $(window).width()  - overflowPos.offset.left - overflowPos.width,
                    bottom: $(window).height() - overflowPos.offset.top  - overflowPos.height,
                    left:   overflowPos.offset.left
                }
              );

        return pos;
    }

    /**
     * Figure where we want to place the popover: right, left, top, bottom, or over
     */
    function getPlacement(elPos) {
        var RequiredSpaceHorizontal = 420;
        var RequiredSpaceVertical   = 300;
        var space = {
            left:   elPos.offset.left,
            right:  $(window).width() - (elPos.offset.left + elPos.width),
            top:    elPos.offset.top - elPos.scrollTop,
            bottom: $(window).height() - (elPos.offset.top - elPos.scrollTop + elPos.height)
        };
        return (space.right >= RequiredSpaceHorizontal || space.left >= RequiredSpaceHorizontal)
             ?  space.right >= space.left ? 'right' : 'left'
             : (space.top   >= RequiredSpaceVertical || space.bottom >= RequiredSpaceVertical)
             ?  space.top   >= space.bottom ? 'top' : 'bottom'
             : 'over';
    }

    /**
     * Adds an "x" at the top right of the popover, so users can close it with a click
     */
    function addClose(controlEl, popover) {
        if (! popover.children('.close').is('*')) {
            var close = $('<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>');
            popover.prepend(close);
            close.on('click', function() { controlEl.popover('destroy'); });
        }
    }

    /**
     * We re-implement the positioning and sizing done by Bootstrap. Instead of indirectly positioning
     * the popover by setting CSS properties on its container, we let Bootstrap give its best shot at
     * positioning and sizing, and we then adjust what Bootstrap did. Bootstrap code is in:
     * https://github.com/twbs/bootstrap/blob/v2.3.2/js/bootstrap-tooltip.js
     *
     * [1] It is unclear to my why we need to add the arrow width, as it should be counted in the width
     *     of the popover, which has a margin to reserve space for the arrow.
     * [2] Bootstrap already positioned the popover mostly correctly, but since we can reduced its
     *     height, in case we do this might remove the need to a scrollbar, which changes the right offset
     *     of the control (e.g. when they are centered), and consequently the right offset of the popover
     *     also needs to be adjusted.
     */
    function positionPopover(popover, placement, elPos) {
        var padding       = 20; // Space left between popover and document border
        var arrowWidth    = popover.children('.arrow').outerWidth(); // [1]
        var arrowHeight   = popover.children('.arrow').outerHeight();

        // Constraint height if taller than viewport
        var maxHeight =
            // When left/right, viewport height sets the limit
            _.contains(['right', 'left', 'over'], placement) ?
                $(window).height() - 2*padding - elPos.margins.top - elPos.margins.bottom
            // When bottom, space below
            : placement == 'bottom' ?
                $(window).height() - (elPos.offset.top - elPos.scrollTop + elPos.height + arrowHeight + padding)
            // When top, space above
            : elPos.offset.top - elPos.scrollTop - padding - arrowHeight;
        if (popover.outerHeight() > maxHeight) {
            var title   = popover.children('.popover-title');
            var content = popover.children('.popover-content');
            popover.css('height', maxHeight + 'px');
            content.css('height', (maxHeight - title.outerHeight()) + 'px');
        }

        // Adjust position
        var popoverOffset = popover.offset();
        popoverOffset.top = (function() {
            switch (true) {
                case _.contains(['right', 'left'], placement) && (popoverOffset.top - elPos.scrollTop < padding):
                    return elPos.margins.top + elPos.scrollTop + padding;
                case placement == 'top':
                    return elPos.offset.top - popover.outerHeight() - arrowHeight;
                case placement == 'over':
                    return elPos.offset.top + padding;
                default:
                    return popoverOffset.top;
            }
        })();
        popoverOffset.left = (function() {
            switch (true) {
                case placement == 'right':
                    return elPos.offset.left + elPos.width + arrowWidth
                case placement == 'left':
                    return elPos.offset.left - popover.outerWidth() - arrowWidth
                case _.contains(['top', 'bottom'], placement):
                    return elPos.offset.left
                case placement == 'over':
                    return elPos.offset.left + elPos.width - popover.outerWidth() - padding;
                default:
                    return popoverOffset.top;
            }
        })();
        popover.offset(popoverOffset);

        // Adjust arrow height for right/left
        if (_.contains(['right', 'left'], placement)) {
            var controlTopDoc = elPos.offset.top + elPos.height/2;
            var controlTopPopover = controlTopDoc - popoverOffset.top;
            var arrowTop = (controlTopPopover / popover.outerHeight()) * 100;
            popover.children('.arrow').css('top', arrowTop + '%');
        } else if (_.contains(['top', 'bottom'], placement)) {
            popover.children('.arrow').css('left', '10%');
        }
    }

    // Hide help when users press the escape key
    $(document).keyup(function(e) {
        if (e.keyCode == 27) { hideAllHelpPopovers(); }
    });
})();<commit_msg>Better positioning of help for section title<commit_after>/**
 * Copyright (C) 2013 Orbeon, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */

(function() {

    var Controls = ORBEON.xforms.Controls;

    /**
     * We're asked to show the help popover for a control, either because the user clicked on the help icon,
     * or because the server asks us to do so.
     *
     * [1] We want the arrow to point to the form field, not somewhere between the label and the field,
     *     hence here we look for the first element which is not an LHHA. If we don't find any such element
     *     we use the container as a fallback (e.g. xf:group that only contains the help and a label).
     * [2] Using animation unnecessarily complicates things, by creating cases where we have two popovers
     *     in the DOM, when one is being hidden while the other is being shown, so we just disable animations.
     */
    Controls.showHelp = function(controlEl) {

        controlEl = $(controlEl);
        var labelText           = $(Controls.getControlLHHA(controlEl, 'label')).text();
        var helpText            = $(Controls.getControlLHHA(controlEl, 'help' )).text();
        var firstChildFormEl    = controlEl.find(':input').first();
        var el                  = firstChildFormEl.is('*') ? firstChildFormEl : controlEl; // [1]
        var elPos               = getPosition(el);
        var placement           = getPlacement(elPos);
        var popoverAlreadyShown = controlEl.next().is('.xforms-help-popover');

        // Hide other help popovers before (maybe) showing this one
        hideAllHelpPopovers();

        // We take users asking to show the popover when already shown as an order to hide it
        if (! popoverAlreadyShown) {

            // For top placement, popover must be above the label
            if (placement == 'top') {
                el = controlEl;
                elPos = getPosition(el);
            }

            controlEl.popover({
                placement: placement,
                trigger:   'manual',
                title:     labelText,
                content:   helpText,
                html:      true,
                animation: false // [2]
            }).popover('show');

            // Decorate an position popover
            var popover = $(controlEl).next();
            popover.addClass('xforms-help-popover');
            addClose(controlEl, popover);
            positionPopover(popover, placement, elPos);
        }
    };

    function hideAllHelpPopovers() {
        _.each($('form.xforms-form .xforms-help-popover'), function(popover) {
            $(popover).prev().popover('destroy');
        });
    }

    /**
     * Get offset/width/height of element, dealing with case where element is inline
     */
    function getPosition(el) {
        function getElPosition() {
            return {
                offset:    el.offset(),
                width :    el.outerWidth(),
                height:    el.outerHeight(),
                scrollTop: $(document).scrollTop() // Will this work if we're in a scrollable area?
            }
        }

        var pos;
        if (el.is(':hidden')) {
            var originalStyle = el.attr('style');
            el.css('display', 'inline-block');
            pos = getElPosition();
            (_.isUndefined(originalStyle))
                ? el.removeAttr('style')
                : el.attr('style', originalStyle);
        } else {
            pos = getElPosition();
        }

        var overflowEl = $(_.find($(el).parents(), function(e) { return $(e).css('overflow') == 'auto'; }));
        var overflowPos = {};
        pos.margins = ! overflowEl.is('*')
            ? { top: 0, right: 0, bottom: 0, left: 0 }
            : (
                overflowPos.offset = overflowEl.offset(),
                overflowPos.width  = overflowEl.outerWidth(),
                overflowPos.height = overflowEl.outerHeight(),
                {
                    top:    overflowPos.offset.top,
                    right:  $(window).width()  - overflowPos.offset.left - overflowPos.width,
                    bottom: $(window).height() - overflowPos.offset.top  - overflowPos.height,
                    left:   overflowPos.offset.left
                }
              );

        return pos;
    }

    /**
     * Figure where we want to place the popover: right, left, top, bottom, or over
     */
    function getPlacement(elPos) {
        var RequiredSpaceHorizontal = 420;
        var RequiredSpaceVertical   = 300;
        var space = {
            left:   elPos.offset.left,
            right:  $(window).width() - (elPos.offset.left + elPos.width),
            top:    elPos.offset.top - elPos.scrollTop,
            bottom: $(window).height() - (elPos.offset.top - elPos.scrollTop + elPos.height)
        };
        return (space.right >= RequiredSpaceHorizontal || space.left >= RequiredSpaceHorizontal)
             ?  space.right >= space.left ? 'right' : 'left'
             : (space.top   >= RequiredSpaceVertical || space.bottom >= RequiredSpaceVertical)
             ?  space.top   >= space.bottom ? 'top' : 'bottom'
             : 'over';
    }

    /**
     * Adds an "x" at the top right of the popover, so users can close it with a click
     */
    function addClose(controlEl, popover) {
        if (! popover.children('.close').is('*')) {
            var close = $('<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>');
            popover.prepend(close);
            close.on('click', function() { controlEl.popover('destroy'); });
        }
    }

    /**
     * We re-implement the positioning and sizing done by Bootstrap. Instead of indirectly positioning
     * the popover by setting CSS properties on its container, we let Bootstrap give its best shot at
     * positioning and sizing, and we then adjust what Bootstrap did. Bootstrap code is in:
     * https://github.com/twbs/bootstrap/blob/v2.3.2/js/bootstrap-tooltip.js
     *
     * [1] It is unclear to my why we need to add the arrow width, as it should be counted in the width
     *     of the popover, which has a margin to reserve space for the arrow.
     * [2] Bootstrap already positioned the popover mostly correctly, but since we can reduced its
     *     height, in case we do this might remove the need to a scrollbar, which changes the right offset
     *     of the control (e.g. when they are centered), and consequently the right offset of the popover
     *     also needs to be adjusted.
     */
    function positionPopover(popover, placement, elPos) {
        var padding       = 20; // Space left between popover and document border
        var arrowWidth    = popover.children('.arrow').outerWidth(); // [1]
        var arrowHeight   = popover.children('.arrow').outerHeight();

        // Constraint height if taller than viewport
        var maxHeight =
            // When left/right, viewport height sets the limit
            _.contains(['right', 'left', 'over'], placement) ?
                $(window).height() - 2*padding - elPos.margins.top - elPos.margins.bottom
            // When bottom, space below
            : placement == 'bottom' ?
                $(window).height() - (elPos.offset.top - elPos.scrollTop + elPos.height + arrowHeight + padding)
            // When top, space above
            : elPos.offset.top - elPos.scrollTop - padding - arrowHeight;
        if (popover.outerHeight() > maxHeight) {
            var title   = popover.children('.popover-title');
            var content = popover.children('.popover-content');
            popover.css('height', maxHeight + 'px');
            content.css('height', (maxHeight - title.outerHeight()) + 'px');
        }

        // Adjust position
        var popoverOffset = popover.offset();
        popoverOffset.top = (function() {
            switch (true) {
                case _.contains(['right', 'left'], placement) && (popoverOffset.top - elPos.scrollTop < padding):
                    return elPos.margins.top + elPos.scrollTop + padding;
                case placement == 'top':
                    return elPos.offset.top - popover.outerHeight() - arrowHeight;
                case placement == 'over':
                    return elPos.offset.top + padding;
                default:
                    return popoverOffset.top;
            }
        })();
        popoverOffset.left = (function() {
            switch (true) {
                case placement == 'right':
                    return elPos.offset.left + elPos.width + arrowWidth
                case placement == 'left':
                    return elPos.offset.left - popover.outerWidth() - arrowWidth
                case _.contains(['top', 'bottom'], placement):
                    return elPos.offset.left
                case placement == 'over':
                    return elPos.offset.left + elPos.width - popover.outerWidth() - padding;
                default:
                    return popoverOffset.top;
            }
        })();
        popover.offset(popoverOffset);

        // Adjust arrow height for right/left
        if (_.contains(['right', 'left'], placement)) {
            var controlTopDoc = elPos.offset.top + elPos.height/2;
            var controlTopPopover = controlTopDoc - popoverOffset.top;
            var arrowTop = (controlTopPopover / popover.outerHeight()) * 100;
            popover.children('.arrow').css('top', arrowTop + '%');
        } else if (_.contains(['top', 'bottom'], placement)) {
            popover.children('.arrow').css('left', '10%');
        }
    }

    // Hide help when users press the escape key
    $(document).keyup(function(e) {
        if (e.keyCode == 27) { hideAllHelpPopovers(); }
    });
})();<|endoftext|>


<commit_before>/**
 * Client tests
 */
import { curry, flow, forEach } from "lodash";
import { mount } from "enzyme";
import React from "react";
import { addEvents } from "src/index";
import VictorySharedEvents from "src/victory-shared-events/victory-shared-events";
import { MockVictoryComponent, MockDataComponent } from "../mock-components";

describe.only("components/victory-shared-events", () => {
  const EventedMockVictoryComponent = addEvents(MockVictoryComponent);

  const findComponentByName = (name, component) => {
    // workaround for nonfunctional prop selector on mounted components
    // https://github.com/airbnb/enzyme/issues/534
    return component.findWhere((node) => {
      return node.prop('name') === name;
    });
  };

  const expectEventEffects = (expectationMatrix, testFn, component) => {
    forEach(expectationMatrix, (dataComponentExpectations, parentComponentName) => {
      const dataComponentTests = findComponentByName(parentComponentName, component)
        .find(MockDataComponent)
        .map(testFn);

      expect(dataComponentTests).to.eql(dataComponentExpectations);
    });
  };

  const findDataComponent = (parentName, index, component) => {
    return findComponentByName(parentName, component)
      .find(MockDataComponent)
      .at(index);
  };

  it("should trigger shared events exclusively on selected children", () => {
    const data = [
      {x: "a", y: 2},
      {x: "b", y: 3},
      {x: "c", y: 5},
      {x: "d", y: 4}
    ];
    const wrapper = mount(
      <svg>
        <VictorySharedEvents
          events={[{
            childName: ["one", "two"],
            target: "data",
            eventHandlers: {
              onClick: () => {
                return [{
                  childName: ["one", "three"],
                  mutation: (props) => {
                    return {
                      style: Object.assign({}, props.style, {fill: "tomato"})
                    };
                  }
                }];
              }
            }
          }]}
        >
          <EventedMockVictoryComponent name="one" data={data} />
          <EventedMockVictoryComponent name="two" data={data} />
          <EventedMockVictoryComponent name="three" data={data} />
        </VictorySharedEvents>
      </svg>
    );

    const eventTriggeredOnComponent = (component) => {
      return component.props().style.fill === "tomato";
    };

    // Expect no events triggered at beginning.
    expectEventEffects({
      one: [false, false, false, false],
      two: [false, false, false, false],
      three: [false, false, false, false]
    }, eventTriggeredOnComponent, wrapper);

    findDataComponent("one", 0, wrapper).simulate("click");

    // First child data components trigger effects on first and third
    expectEventEffects({
      one: [true, false, false, false],
      two: [false, false, false, false],
      three: [true, false, false, false]
    }, eventTriggeredOnComponent, wrapper);

    findDataComponent("two", 1, wrapper).simulate("click");

    // Second child data components trigger effects on first and third
    expectEventEffects({
      one: [true, true, false, false],
      two: [false, false, false, false],
      three: [true, true, false, false]
    }, eventTriggeredOnComponent, wrapper);

    findDataComponent("three", 2, wrapper).simulate("click");

    // Third child data components do not trigger effects
    expectEventEffects({
      one: [true, true, false, false],
      two: [false, false, false, false],
      three: [true, true, false, false]
    }, eventTriggeredOnComponent, wrapper);
  });
});
<commit_msg>use .prop() instead of .props()<commit_after>/**
 * Client tests
 */
import { curry, flow, forEach } from "lodash";
import { mount } from "enzyme";
import React from "react";
import { addEvents } from "src/index";
import VictorySharedEvents from "src/victory-shared-events/victory-shared-events";
import { MockVictoryComponent, MockDataComponent } from "../mock-components";

describe.only("components/victory-shared-events", () => {
  const EventedMockVictoryComponent = addEvents(MockVictoryComponent);

  const findComponentByName = (name, component) => {
    // workaround for nonfunctional prop selector on mounted components
    // https://github.com/airbnb/enzyme/issues/534
    return component.findWhere((node) => {
      return node.prop('name') === name;
    });
  };

  const expectEventEffects = (expectationMatrix, testFn, component) => {
    forEach(expectationMatrix, (dataComponentExpectations, parentComponentName) => {
      const dataComponentTests = findComponentByName(parentComponentName, component)
        .find(MockDataComponent)
        .map(testFn);

      expect(dataComponentTests).to.eql(dataComponentExpectations);
    });
  };

  const findDataComponent = (parentName, index, component) => {
    return findComponentByName(parentName, component)
      .find(MockDataComponent)
      .at(index);
  };

  it("should trigger shared events exclusively on selected children", () => {
    const data = [
      {x: "a", y: 2},
      {x: "b", y: 3},
      {x: "c", y: 5},
      {x: "d", y: 4}
    ];
    const wrapper = mount(
      <svg>
        <VictorySharedEvents
          events={[{
            childName: ["one", "two"],
            target: "data",
            eventHandlers: {
              onClick: () => {
                return [{
                  childName: ["one", "three"],
                  mutation: (props) => {
                    return {
                      style: Object.assign({}, props.style, {fill: "tomato"})
                    };
                  }
                }];
              }
            }
          }]}
        >
          <EventedMockVictoryComponent name="one" data={data} />
          <EventedMockVictoryComponent name="two" data={data} />
          <EventedMockVictoryComponent name="three" data={data} />
        </VictorySharedEvents>
      </svg>
    );

    const eventTriggeredOnComponent = (component) => {
      return component.prop('style').fill === "tomato";
    };

    // Expect no events triggered at beginning.
    expectEventEffects({
      one: [false, false, false, false],
      two: [false, false, false, false],
      three: [false, false, false, false]
    }, eventTriggeredOnComponent, wrapper);

    findDataComponent("one", 0, wrapper).simulate("click");

    // First child data components trigger effects on first and third
    expectEventEffects({
      one: [true, false, false, false],
      two: [false, false, false, false],
      three: [true, false, false, false]
    }, eventTriggeredOnComponent, wrapper);

    findDataComponent("two", 1, wrapper).simulate("click");

    // Second child data components trigger effects on first and third
    expectEventEffects({
      one: [true, true, false, false],
      two: [false, false, false, false],
      three: [true, true, false, false]
    }, eventTriggeredOnComponent, wrapper);

    findDataComponent("three", 2, wrapper).simulate("click");

    // Third child data components do not trigger effects
    expectEventEffects({
      one: [true, true, false, false],
      two: [false, false, false, false],
      three: [true, true, false, false]
    }, eventTriggeredOnComponent, wrapper);
  });
});
<|endoftext|>


<commit_before>import Ember from 'ember';
import BaseEditFormController from 'ember-flexberry/controllers/edit-form';
import EditFormControllerOperationsIndicationMixin from 'ember-flexberry/mixins/edit-form-controller-operations-indication';

export default BaseEditFormController.extend(EditFormControllerOperationsIndicationMixin, {
  /**
    Route name for transition after close edit form.

    @property parentRoute
    @type String
    @default 'ember-flexberry-dummy-suggestion-list'
   */
  parentRoute: 'ember-flexberry-dummy-suggestion-list',

  /**
    Name of model.comments edit route.

    @property commentsEditRoute
    @type String
    @default 'ember-flexberry-dummy-comment-edit'
   */
  commentsEditRoute: 'ember-flexberry-dummy-comment-edit',

  /**
    Method to get type and attributes of a component,
    which will be embeded in object-list-view cell.

    @method getCellComponent.
    @param {Object} attr Attribute of projection property related to current table cell.
    @param {String} bindingPath Path to model property related to current table cell.
    @param {DS.Model} modelClass Model class of data record related to current table row.
    @return {Object} Object containing name & properties of component, which will be used to render current table cell.
    { componentName: 'my-component',  componentProperties: { ... } }.
   */
  getCellComponent(attr, bindingPath, model) {
    let cellComponent = this._super(...arguments);
    if (attr.kind === 'belongsTo') {
      switch (`${model.modelName}+${bindingPath}`) {
        case 'ember-flexberry-dummy-vote+author':
          cellComponent.componentProperties = {
            choose: 'showLookupDialog',
            remove: 'removeLookupValue',
            displayAttributeName: 'name',
            required: true,
            relationName: 'author',
            projection: 'ApplicationUserL',
            autocomplete: true,
            lookupWindowCustomProperties: () => { return { filterButton: true, refreshButton: true }; },
          };
          break;

        case 'ember-flexberry-dummy-comment+author':
          cellComponent.componentProperties = {
            choose: 'showLookupDialog',
            remove: 'removeLookupValue',
            displayAttributeName: 'name',
            required: true,
            relationName: 'author',
            projection: 'ApplicationUserL',
            autocomplete: true,
          };
          break;

      }
    }

    return cellComponent;
  },

  actions: {
    configurateFilesRow(rowConfig, record) {
      Ember.set(rowConfig, 'customClass', 'positive ');
      let readonlyColumns = [];
      if (record.get('order') === 1) {
        readonlyColumns.push('order');
        readonlyColumns.push('file');
      }

      Ember.set(rowConfig, 'readonlyColumns', readonlyColumns);
    },

    configurateVotesRow(rowConfig, record) {
      let readonlyColumns = [];
      if (record.get('author.name') === 'Иван') {
        readonlyColumns.push('author');
      }

      Ember.set(rowConfig, 'readonlyColumns', readonlyColumns);
    }
  }
});
<commit_msg>Add lookupLimitPredicate<commit_after>import Ember from 'ember';
import BaseEditFormController from 'ember-flexberry/controllers/edit-form';
import EditFormControllerOperationsIndicationMixin from 'ember-flexberry/mixins/edit-form-controller-operations-indication';
import { Query } from 'ember-flexberry-data';

const { StringPredicate } = Query;

export default BaseEditFormController.extend(EditFormControllerOperationsIndicationMixin, {
  /**
    Route name for transition after close edit form.

    @property parentRoute
    @type String
    @default 'ember-flexberry-dummy-suggestion-list'
   */
  parentRoute: 'ember-flexberry-dummy-suggestion-list',

  /**
    Name of model.comments edit route.

    @property commentsEditRoute
    @type String
    @default 'ember-flexberry-dummy-comment-edit'
   */
  commentsEditRoute: 'ember-flexberry-dummy-comment-edit',

  /**
    Method to get type and attributes of a component,
    which will be embeded in object-list-view cell.

    @method getCellComponent.
    @param {Object} attr Attribute of projection property related to current table cell.
    @param {String} bindingPath Path to model property related to current table cell.
    @param {DS.Model} modelClass Model class of data record related to current table row.
    @return {Object} Object containing name & properties of component, which will be used to render current table cell.
    { componentName: 'my-component',  componentProperties: { ... } }.
   */
  getCellComponent(attr, bindingPath, model) {
    let limitFunction = new StringPredicate('name').contains('ва');
    let cellComponent = this._super(...arguments);
    if (attr.kind === 'belongsTo') {
      switch (`${model.modelName}+${bindingPath}`) {
        case 'ember-flexberry-dummy-vote+author':
          cellComponent.componentProperties = {
            choose: 'showLookupDialog',
            remove: 'removeLookupValue',
            displayAttributeName: 'name',
            required: true,
            relationName: 'author',
            projection: 'ApplicationUserL',
            autocomplete: true,
            lookupLimitPredicate: limitFunction,
            readonly: true
          };
          break;

        case 'ember-flexberry-dummy-comment+author':
          cellComponent.componentProperties = {
            choose: 'showLookupDialog',
            remove: 'removeLookupValue',
            displayAttributeName: 'name',
            required: true,
            relationName: 'author',
            projection: 'ApplicationUserL',
            autocomplete: true,
          };
          break;

      }
    }

    return cellComponent;
  },

  actions: {
    configurateFilesRow(rowConfig, record) {
      Ember.set(rowConfig, 'customClass', 'positive ');
      let readonlyColumns = [];
      if (record.get('order') === 1) {
        readonlyColumns.push('order');
        readonlyColumns.push('file');
      }

      Ember.set(rowConfig, 'readonlyColumns', readonlyColumns);
    },

    configurateVotesRow(rowConfig, record) {
      let readonlyColumns = [];
      if (record.get('author.name') === 'Иван') {
        readonlyColumns.push('author');
      }

      Ember.set(rowConfig, 'readonlyColumns', readonlyColumns);
    }
  }
});
<|endoftext|>