<commit_before>/*
 * MBP - Mobile boilerplate helper functions
 */
(function(document){

window.MBP = window.MBP || {};

// Fix for iPhone viewport scale bug
// http://www.blog.highub.com/mobile-2/a-fix-for-iphone-viewport-scale-bug/

MBP.viewportmeta = document.querySelector && document.querySelector('meta[name="viewport"]');
MBP.ua = navigator.userAgent;

MBP.scaleFix = function () {
  if (MBP.viewportmeta && /iPhone|iPad|iPod/.test(MBP.ua) && !/Opera Mini/.test(MBP.ua)) {
    MBP.viewportmeta.content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
    document.addEventListener("gesturestart", MBP.gestureStart, false);
  }
};
MBP.gestureStart = function () {
  MBP.viewportmeta.content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
};

/*
  * Normalized hide address bar for iOS & Android
  * (c) Scott Jehl, scottjehl.com
  * MIT License
*/

// If we split this up into two functions we can reuse
// this function if we aren't doing full page reloads.

// If we cache this we don't need to re-calibrate everytime we call
// the hide url bar
MBP.BODY_SCROLL_TOP = false;

// So we don't redefine this function everytime we
// we call hideUrlBar
MBP.getScrollTop = function(){
  var win = window,
      doc = document;

  return win.pageYOffset || doc.compatMode === "CSS1Compat" && doc.documentElement.scrollTop || doc.body.scrollTop || 0;
};

// It should be up to the mobile
MBP.hideUrlBar = function(){
    var win = window;

    // if there is a hash, or MBP.BODY_SCROLL_TOP hasn't been set yet, wait till that happens
    if( !location.hash && MBP.BODY_SCROLL_TOP !== false){
        win.scrollTo( 0, MBP.BODY_SCROLL_TOP === 1 ? 0 : 1 );
    }
};

MBP.hideUrlBarOnLoad = function () {
  var win = window,
      doc = win.document;

  // If there's a hash, or addEventListener is undefined, stop here
  if( !location.hash && win.addEventListener ) {

    //scroll to 1
    window.scrollTo( 0, 1 );
    MBP.BODY_SCROLL_TOP = 1;

    //reset to 0 on bodyready, if needed
    bodycheck = setInterval(function() {
      if( doc.body ) {
        clearInterval( bodycheck );
        MBP.BODY_SCROLL_TOP = MBP.getScrollTop();
        MBP.hideUrlBar();
      }
    }, 15 );

    win.addEventListener( "load", function() {
      setTimeout(function() {
        //at load, if user hasn't scrolled more than 20 or so...
        if( MBP.getScrollTop() < 20 ) {
          //reset to hide addr bar at onload
          MBP.hideUrlBar();
        }
      }, 0);
    } );
  }
};

// Fast Buttons - read wiki below before using
// https://github.com/h5bp/mobile-boilerplate/wiki/JavaScript-Helper
MBP.fastButton = function (element, handler) {
  this.handler = handler;

	if (element.length && element.length > 1) {
    for (var singleElIdx in element) {
      if (element[singleElIdx].addEventListener) {
        this.addClickEvent(element[singleElIdx]);
      }
    }
  } else if (element.addEventListener) {
    this.addClickEvent(element);
  }
};

MBP.fastButton.prototype.handleEvent = function(event) {
	event = event || window.event;
  switch (event.type) {
    case 'touchstart': this.onTouchStart(event); break;
    case 'touchmove': this.onTouchMove(event); break;
    case 'touchend': this.onClick(event); break;
    case 'click': this.onClick(event); break;
  }
};

MBP.fastButton.prototype.onTouchStart = function(event) {
  var element = event.srcElement;
  event.stopPropagation();
  element.addEventListener('touchend', this, false);
  document.body.addEventListener('touchmove', this, false);
  this.startX = event.touches[0].clientX;
  this.startY = event.touches[0].clientY;
  element.style.backgroundColor = "rgba(0,0,0,.7)";
};

MBP.fastButton.prototype.onTouchMove = function(event) {
  if(Math.abs(event.touches[0].clientX - this.startX) > 10 ||
    Math.abs(event.touches[0].clientY - this.startY) > 10    ) {
    this.reset(element);
  }
};

MBP.fastButton.prototype.onClick = function(event) {
	event = event || window.event;
  var element = event.srcElement;
  if (event.stopPropagation) { event.stopPropagation(); }
  this.reset(event);
  this.handler.apply(event.currentTarget, [event]);
  if(event.type == 'touchend') {
    MBP.preventGhostClick(this.startX, this.startY);
  }
  element.style.backgroundColor = "";
};

MBP.fastButton.prototype.reset = function() {
	rmEvt(element, "touchend", this, false);
	rmEvt(document.body, "touchmove", this, false);
  element.style.backgroundColor = "";
};

MBP.fastButton.prototype.addClickEvent = function(element) {
  addEvt(element, "touchstart", this, false);
  addEvt(element, "click", this, false);
};

MBP.preventGhostClick = function (x, y) {
  MBP.coords.push(x, y);
  window.setTimeout(function (){
    MBP.coords.splice(0, 2);
  }, 2500);
};

MBP.ghostClickHandler = function (event) {
  if (!MBP.hadTouchEvent && 'ontouchstart' in window) {
    // This is a bit of fun for Android 2.3...
    // If you change window.location via fastButton, a click event will fire
    // on the new page, as if the events are continuing from the previous page.
    // We pick that event up here, but MBP.coords is empty, because it's a new page,
    // so we don't prevent it. Here's we're assuming that click events on touch devices
    // that occur without a preceding touchStart are to be ignored.
    event.stopPropagation();
    event.preventDefault();
    return;
  }
  for(var i = 0, len = MBP.coords.length; i < len; i += 2) {
    var x = MBP.coords[i];
    var y = MBP.coords[i + 1];
    if(Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
      event.stopPropagation();
      event.preventDefault();
    }
  }
};

if (document.addEventListener) {
  document.addEventListener('click', MBP.ghostClickHandler, true);
}

addEvt( document.documentElement, 'touchstart', function() {
  MBP.hadTouchEvent = true;
}, false);

MBP.coords = [];

// fn arg can be an object or a function, thanks to handleEvent
// read more about the explanation at: http://www.thecssninja.com/javascript/handleevent
function addEvt(el, evt, fn, bubble) {
  if("addEventListener" in el) {
    // BBOS6 doesn't support handleEvent, catch and polyfill
    try {
      el.addEventListener(evt, fn, bubble);
    } catch(e) {
      if(typeof fn == "object" && fn.handleEvent) {
        el.addEventListener(evt, function(e){
        // Bind fn as this and set first arg as event object
        fn.handleEvent.call(fn,e);
        }, bubble);
      } else {
        throw e;
      }
    }
  } else if("attachEvent" in el) {
    // check if the callback is an object and contains handleEvent
    if(typeof fn == "object" && fn.handleEvent) {
      el.attachEvent("on" + evt, function(){
        // Bind fn as this
        fn.handleEvent.call(fn);
      });
    } else {
      el.attachEvent("on" + evt, fn);
    }
  }
}

function rmEvt(el, evt, fn, bubble) {
  if("removeEventListener" in el) {
    // BBOS6 doesn't support handleEvent, catch and polyfill
    try {
      el.removeEventListener(evt, fn, bubble);
    } catch(e) {
      if(typeof fn == "object" && fn.handleEvent) {
        el.removeEventListener(evt, function(e){
          // Bind fn as this and set first arg as event object
          fn.handleEvent.call(fn,e);
        }, bubble);
      } else {
        throw e;
      }
    }
  } else if("detachEvent" in el) {
    // check if the callback is an object and contains handleEvent
    if(typeof fn == "object" && fn.handleEvent) {
      el.detachEvent("on" + evt, function(){
        // Bind fn as this
        fn.handleEvent.call(fn);
      });
    } else {
      el.detachEvent("on" + evt, fn);
    }
  }
}

// iOS Startup Image
// https://github.com/h5bp/mobile-boilerplate/issues#issue/2

MBP.splash = function () {
  var filename = navigator.platform === 'iPad' ? 'h/' : 'l/';
  document.write('<link rel="apple-touch-startup-image" href="/img/' + filename + 'splash.png" />' );
};

// Autogrow
// http://googlecode.blogspot.com/2009/07/gmail-for-mobile-html5-series.html

MBP.autogrow = function (element, lh) {
  function handler(e){
    var newHeight = this.scrollHeight,
        currentHeight = this.clientHeight;
    if (newHeight > currentHeight) {
      this.style.height = newHeight + 3 * textLineHeight + "px";
    }
  }

  var setLineHeight = (lh) ? lh : 12,
      textLineHeight = element.currentStyle ? element.currentStyle.lineHeight :
                       getComputedStyle(element, null).lineHeight;

  textLineHeight = (textLineHeight.indexOf("px") == -1) ? setLineHeight :
                   parseInt(textLineHeight, 10);

  element.style.overflow = "hidden";
  element.addEventListener ? element.addEventListener('keyup', handler, false) :
                             element.attachEvent('onkeyup', handler);
};

// Enable active
// Enable CSS active pseudo styles in Mobile Safari
// http://miniapps.co.uk/blog/post/enable-css-active-pseudo-styles-in-mobile-safari/
MBP.enableActive = function () {
  document.addEventListener("touchstart", function() {}, false);
};

// Prevent iOS from zooming onfocus
// https://github.com/h5bp/mobile-boilerplate/pull/108
MBP.preventZoom = function () {
  var formFields = document.querySelectorAll('input, select, textarea'),
  	  contentString = 'width=device-width,initial-scale=1,maximum-scale=',
  	  i = 0;
  for(i = 0; i < formFields.length; i++) {
    formFields[i].onfocus = function() {
      MBP.viewportmeta.content = contentString + '1';
    };
    formFields[i].onblur = function() {
      MBP.viewportmeta.content = contentString + '10';
    };
  }
};

// Original jQuery snippet for Prevent iOS from zooming onfocus
// http://nerd.vasilis.nl/prevent-ios-from-zooming-onfocus/
// $('input, select, textarea').bind('focus blur', function(event) {
//	MBP.viewportmeta.content = 'width=device-width,initial-scale=1,maximum-scale=' + (event.type == 'blur' ? 10 : 1);
// });

})(document);
<commit_msg>modified comment format in helper.js<commit_after>/*
 * MBP - Mobile boilerplate helper functions
 */

(function(document){

window.MBP = window.MBP || {};

/*
  * Fix for iPhone viewport scale bug
  * http://www.blog.highub.com/mobile-2/a-fix-for-iphone-viewport-scale-bug/
*/

MBP.viewportmeta = document.querySelector && document.querySelector('meta[name="viewport"]');
MBP.ua = navigator.userAgent;

MBP.scaleFix = function () {
  if (MBP.viewportmeta && /iPhone|iPad|iPod/.test(MBP.ua) && !/Opera Mini/.test(MBP.ua)) {
    MBP.viewportmeta.content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
    document.addEventListener("gesturestart", MBP.gestureStart, false);
  }
};
MBP.gestureStart = function () {
  MBP.viewportmeta.content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
};

/*
  * Normalized hide address bar for iOS & Android
  * (c) Scott Jehl, scottjehl.com
  * MIT License
*/

// If we split this up into two functions we can reuse
// this function if we aren't doing full page reloads.

// If we cache this we don't need to re-calibrate everytime we call
// the hide url bar
MBP.BODY_SCROLL_TOP = false;

// So we don't redefine this function everytime we
// we call hideUrlBar
MBP.getScrollTop = function(){
  var win = window,
      doc = document;

  return win.pageYOffset || doc.compatMode === "CSS1Compat" && doc.documentElement.scrollTop || doc.body.scrollTop || 0;
};

// It should be up to the mobile
MBP.hideUrlBar = function(){
    var win = window;

    // if there is a hash, or MBP.BODY_SCROLL_TOP hasn't been set yet, wait till that happens
    if( !location.hash && MBP.BODY_SCROLL_TOP !== false){
        win.scrollTo( 0, MBP.BODY_SCROLL_TOP === 1 ? 0 : 1 );
    }
};

MBP.hideUrlBarOnLoad = function () {
  var win = window,
      doc = win.document;

  // If there's a hash, or addEventListener is undefined, stop here
  if( !location.hash && win.addEventListener ) {

    //scroll to 1
    window.scrollTo( 0, 1 );
    MBP.BODY_SCROLL_TOP = 1;

    //reset to 0 on bodyready, if needed
    bodycheck = setInterval(function() {
      if( doc.body ) {
        clearInterval( bodycheck );
        MBP.BODY_SCROLL_TOP = MBP.getScrollTop();
        MBP.hideUrlBar();
      }
    }, 15 );

    win.addEventListener( "load", function() {
      setTimeout(function() {
        //at load, if user hasn't scrolled more than 20 or so...
        if( MBP.getScrollTop() < 20 ) {
          //reset to hide addr bar at onload
          MBP.hideUrlBar();
        }
      }, 0);
    } );
  }
};

/*
   * Fast Buttons - read wiki below before using
   * https://github.com/h5bp/mobile-boilerplate/wiki/JavaScript-Helper
*/

MBP.fastButton = function (element, handler) {
  this.handler = handler;

	if (element.length && element.length > 1) {
    for (var singleElIdx in element) {
      if (element[singleElIdx].addEventListener) {
        this.addClickEvent(element[singleElIdx]);
      }
    }
  } else if (element.addEventListener) {
    this.addClickEvent(element);
  }
};

MBP.fastButton.prototype.handleEvent = function(event) {
	event = event || window.event;
  switch (event.type) {
    case 'touchstart': this.onTouchStart(event); break;
    case 'touchmove': this.onTouchMove(event); break;
    case 'touchend': this.onClick(event); break;
    case 'click': this.onClick(event); break;
  }
};

MBP.fastButton.prototype.onTouchStart = function(event) {
  var element = event.srcElement;
  event.stopPropagation();
  element.addEventListener('touchend', this, false);
  document.body.addEventListener('touchmove', this, false);
  this.startX = event.touches[0].clientX;
  this.startY = event.touches[0].clientY;
  element.style.backgroundColor = "rgba(0,0,0,.7)";
};

MBP.fastButton.prototype.onTouchMove = function(event) {
  if(Math.abs(event.touches[0].clientX - this.startX) > 10 ||
    Math.abs(event.touches[0].clientY - this.startY) > 10    ) {
    this.reset(element);
  }
};

MBP.fastButton.prototype.onClick = function(event) {
	event = event || window.event;
  var element = event.srcElement;
  if (event.stopPropagation) { event.stopPropagation(); }
  this.reset(event);
  this.handler.apply(event.currentTarget, [event]);
  if(event.type == 'touchend') {
    MBP.preventGhostClick(this.startX, this.startY);
  }
  element.style.backgroundColor = "";
};

MBP.fastButton.prototype.reset = function() {
	rmEvt(element, "touchend", this, false);
	rmEvt(document.body, "touchmove", this, false);
  element.style.backgroundColor = "";
};

MBP.fastButton.prototype.addClickEvent = function(element) {
  addEvt(element, "touchstart", this, false);
  addEvt(element, "click", this, false);
};

MBP.preventGhostClick = function (x, y) {
  MBP.coords.push(x, y);
  window.setTimeout(function (){
    MBP.coords.splice(0, 2);
  }, 2500);
};

MBP.ghostClickHandler = function (event) {
  if (!MBP.hadTouchEvent && 'ontouchstart' in window) {
    // This is a bit of fun for Android 2.3...
    // If you change window.location via fastButton, a click event will fire
    // on the new page, as if the events are continuing from the previous page.
    // We pick that event up here, but MBP.coords is empty, because it's a new page,
    // so we don't prevent it. Here's we're assuming that click events on touch devices
    // that occur without a preceding touchStart are to be ignored.
    event.stopPropagation();
    event.preventDefault();
    return;
  }
  for(var i = 0, len = MBP.coords.length; i < len; i += 2) {
    var x = MBP.coords[i];
    var y = MBP.coords[i + 1];
    if(Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
      event.stopPropagation();
      event.preventDefault();
    }
  }
};

if (document.addEventListener) {
  document.addEventListener('click', MBP.ghostClickHandler, true);
}

addEvt( document.documentElement, 'touchstart', function() {
  MBP.hadTouchEvent = true;
}, false);

MBP.coords = [];

// fn arg can be an object or a function, thanks to handleEvent
// read more about the explanation at: http://www.thecssninja.com/javascript/handleevent
function addEvt(el, evt, fn, bubble) {
  if("addEventListener" in el) {
    // BBOS6 doesn't support handleEvent, catch and polyfill
    try {
      el.addEventListener(evt, fn, bubble);
    } catch(e) {
      if(typeof fn == "object" && fn.handleEvent) {
        el.addEventListener(evt, function(e){
        // Bind fn as this and set first arg as event object
        fn.handleEvent.call(fn,e);
        }, bubble);
      } else {
        throw e;
      }
    }
  } else if("attachEvent" in el) {
    // check if the callback is an object and contains handleEvent
    if(typeof fn == "object" && fn.handleEvent) {
      el.attachEvent("on" + evt, function(){
        // Bind fn as this
        fn.handleEvent.call(fn);
      });
    } else {
      el.attachEvent("on" + evt, fn);
    }
  }
}

function rmEvt(el, evt, fn, bubble) {
  if("removeEventListener" in el) {
    // BBOS6 doesn't support handleEvent, catch and polyfill
    try {
      el.removeEventListener(evt, fn, bubble);
    } catch(e) {
      if(typeof fn == "object" && fn.handleEvent) {
        el.removeEventListener(evt, function(e){
          // Bind fn as this and set first arg as event object
          fn.handleEvent.call(fn,e);
        }, bubble);
      } else {
        throw e;
      }
    }
  } else if("detachEvent" in el) {
    // check if the callback is an object and contains handleEvent
    if(typeof fn == "object" && fn.handleEvent) {
      el.detachEvent("on" + evt, function(){
        // Bind fn as this
        fn.handleEvent.call(fn);
      });
    } else {
      el.detachEvent("on" + evt, fn);
    }
  }
}

/*
  * iOS Startup Image
  * https://github.com/h5bp/mobile-boilerplate/issues#issue/2
*/

MBP.splash = function () {
  var filename = navigator.platform === 'iPad' ? 'h/' : 'l/';
  document.write('<link rel="apple-touch-startup-image" href="/img/' + filename + 'splash.png" />' );
};

/*
  * Autogrow
  * http://googlecode.blogspot.com/2009/07/gmail-for-mobile-html5-series.html
*/

MBP.autogrow = function (element, lh) {
  function handler(e){
    var newHeight = this.scrollHeight,
        currentHeight = this.clientHeight;
    if (newHeight > currentHeight) {
      this.style.height = newHeight + 3 * textLineHeight + "px";
    }
  }

  var setLineHeight = (lh) ? lh : 12,
      textLineHeight = element.currentStyle ? element.currentStyle.lineHeight :
                       getComputedStyle(element, null).lineHeight;

  textLineHeight = (textLineHeight.indexOf("px") == -1) ? setLineHeight :
                   parseInt(textLineHeight, 10);

  element.style.overflow = "hidden";
  element.addEventListener ? element.addEventListener('keyup', handler, false) :
                             element.attachEvent('onkeyup', handler);
};

/*
  * Enable active
  * Enable CSS active pseudo styles in Mobile Safari
  * http://miniapps.co.uk/blog/post/enable-css-active-pseudo-styles-in-mobile-safari/
*/

MBP.enableActive = function () {
  document.addEventListener("touchstart", function() {}, false);
};

/*
  * Prevent iOS from zooming onfocus
  * https://github.com/h5bp/mobile-boilerplate/pull/108
*/

MBP.preventZoom = function () {
  var formFields = document.querySelectorAll('input, select, textarea'),
  	  contentString = 'width=device-width,initial-scale=1,maximum-scale=',
  	  i = 0;
  for(i = 0; i < formFields.length; i++) {
    formFields[i].onfocus = function() {
      MBP.viewportmeta.content = contentString + '1';
    };
    formFields[i].onblur = function() {
      MBP.viewportmeta.content = contentString + '10';
    };
  }
};

/*
  * Original jQuery snippet for Prevent iOS from zooming onfocus
  *  http://nerd.vasilis.nl/prevent-ios-from-zooming-onfocus/
*/
// $('input, select, textarea').bind('focus blur', function(event) {
//	MBP.viewportmeta.content = 'width=device-width,initial-scale=1,maximum-scale=' + (event.type == 'blur' ? 10 : 1);
// });

})(document);
<|endoftext|>


<commit_before>var gulp = require('gulp');
var jshint = require('gulp-jshint');
var contribs = require('gulp-contribs');
var mocha = require('gulp-mocha');

gulp.task('lint', function () {
    gulp.src(['test/specs/**/*.js', '!test/fixtures/**', 'lib/*'])
        .pipe(jshint('test/specs/.jshintrc'))
        .pipe(jshint.reporter('default'))
        .pipe(jshint.reporter('fail'))
});

gulp.task('contribs', function () {
    gulp.src('README.md')
        .pipe(contribs())
        .pipe(gulp.dest("./"))
});

gulp.task('test', function () {
    gulp.src('test/specs/cli-new/*.js')
        .pipe(mocha())
        .pipe(gulp.dest("./"))
});

gulp.task('default', ['lint']);
<commit_msg>Remove gulp-mocha depen<commit_after>var gulp = require('gulp');
var jshint = require('gulp-jshint');
var contribs = require('gulp-contribs');

gulp.task('lint', function () {
    gulp.src(['test/specs/**/*.js', '!test/fixtures/**', 'lib/*'])
        .pipe(jshint('test/specs/.jshintrc'))
        .pipe(jshint.reporter('default'))
        .pipe(jshint.reporter('fail'))
});

gulp.task('contribs', function () {
    gulp.src('README.md')
        .pipe(contribs())
        .pipe(gulp.dest("./"))
});

gulp.task('default', ['lint']);
<|endoftext|>


<commit_before>// Builds the different HTML parts as needed.

// Gets the link/style data.

function getData() {

    var links = [];
    var cssArr = [];

    // To avoid mismatches we're running sychonously.
    // TODO: find async way to do this so it doesn't block browser.
    $.ajaxSetup({async:false});

    // Find all stylesheet <link>s and


<commit_before>/*
Copyright (C) 2008-2009  Arne Goedeke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.

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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
if( typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error( "This browser does not support XMLHttpRequest." )
};
/**
 * @namespace Meteor js connection namespace.
 */
meteor = new Object();
/**
 * Limit for the incoming buffer. When the incoming XMLHttpRequest object buffer grows larger than this, the connection is reinitiated.
 */
meteor.BUFFER_MAX = 1 << 16; // limit for incoming buffer, exceeding this buffer triggers a reconnect
meteor.dismantle = function(xhr) {
	delete xhr.onreadystatechange;
	if (xhr.readyState < 4) {
	    try { xhr.abort(); } catch (e) {};
	}
};
meteor.debug = function() {
	if (window.console && window.console.log) {
		if (window.console.firebug) {
			window.console.log.apply(window, arguments);
		} else { //this is IE
			window.console.log(arguments[0]);
		}
	}
};
/**
 * Meteor connection class. This is usually used with Atom serialization on top. Use psyc.Client if unsure.
 * @param {String} url URL of the Meteor connection endpoint.
 * @param {Function} callback Function to be called when data has been received.
 * @param {Function} error Function to be called when a fatal error occures.
 * @constructor
 * @example
 * var connection;
 * var incoming = function(data) {
 * 	document.write("Received data: " + data);
 * 	connection.send("Hello World.\n");
 * }
 * connection = new meteor.Connection("http://example.org/meteor/", incoming, alert);
 * connection.init();
 */
meteor.Connection = function(url, vars, callback, error) {
    this.url = url;
    this.vars = vars;
    this.buffer = "";
    this.callback = callback;
    this.error = error;
    this.async = true;
    this.pos = 0;
    this.reconnect = 1; // do a reconnect on close
};
meteor.Connection.prototype = {
	reconnect_incoming : function() {
		meteor.debug("reconnecting due to timeout.\n");
		if (this.new_incoming) {
			meteor.dismantle(this.new_incoming);
			delete this.new_incoming;
		}
		if (this.incoming) {
			meteor.dismantle(this.incoming);
			delete this.incoming;
		}
		this.connect_new_incoming();
	},
	new_incoming_state_change : function(xhr) {
		meteor.debug("new_incoming state is " + xhr.readyState);
		// we should check here for buffer length. maybe set a max
		// amount to shut down the main one ungracefully
		if (xhr.readyState >= 3) {
			this.connect_incoming();
		}
	},
	connect_new_incoming : function() {
		if (this.new_incoming) {
			// we already have one new incoming and are waiting for the
			// main one to shut down

			if (this.new_incoming.readyState == 4) {
			// someone is too fast for us.
			// TODO: we have to check for data in new_incoming,
			// not sure what to do with it. we can probably savely
			// parse it in case of atoms.
				meteor.debug("New connection already finished.\n");
			} else return this.connect_incoming();
		}

		meteor.debug("Connecting new incoming.\n");

		var xhr = new XMLHttpRequest();
		this.new_incoming = xhr;

		xhr.open("POST", UTIL.make_url(this.url, this.vars), true);
		// both opera and IE dont handle binary data correctly.
		if (!window.opera && navigator.appName != 'Microsoft Internet Explorer') {
			xhr.setRequestHeader("Content-Type", "application/octet-stream");
		}
		//xhr.overrideMimeType("text/plain; charset=ISO-8859-1");
		if (xhr.overrideMimeType) xhr.overrideMimeType('text/plain; charset=x-user-defined');
		xhr.onreadystatechange = UTIL.make_callback(this, this.new_incoming_state_change);
		xhr.send("");
	},
	set_nonblocking : function() {
		this.async = true;
	},
	set_blocking : function() {
		this.async = false;
	},
	incoming_state_change : function(xhr) {
		var s;

		if (xhr.readyState >= 3) {
			// workaround for IE
			try {
				s = xhr.status;
			} catch(e) {
				// this is ie country
				// this is ie
				meteor.debug("fucking ie");
			}

			if (s == 200) {
				var length = xhr.responseBody ? xhr.responseBody.length : xhr.responseText.length;

				if (length > this.pos) {
					meteor.debug((length-this.pos)+" bytes received in readyState "+xhr.readyState);
					var str;

					try {
						if (window.opera) {
							str = xhr.responseText.slice(this.pos);
						} else if (xhr.responseBody) {
							str = xhr.responseBody.join("");
						} else {
							str = xhr.responseText.slice(this.pos);
							var t = str.split("");
							for (var i = 0; i < str.length; i++) {
								t[i] = t[i].charCodeAt(0) & 0xff;
							}
							str = String.fromCharCode.apply(window, t);
						}

						meteor.debug("calling callback: %o with %db of data", this.callback, str.length);
						this.callback(str);
					} catch (error) {
						meteor.debug("ERROR: "+error);
					}

					this.pos = length;
				}

				if (xhr.readyState == 4 || this.pos >= meteor.BUFFER_MAX) {
					if (this.operatimer) {
						clearTimeout(this.operatimer);
						delete this.operatimer;
					}
					if (this.reconnect) this.connect_new_incoming();
				}
			} else {
			// this throws an exception in firefox. brain
			//	con.error(this.statusText);
			}
		}
	},
	incoming_on_error : function() {
		meteor.debug("INCOMING ERROR!");
		window.setTimeout(UTIL.make_callback(this, this.connect_new_incoming), 500);
	},
	connect_incoming : function(xhr) {
		if (!xhr) {
			if (this.new_incoming) {
				xhr = this.new_incoming;
			} else throw("you need to call new_incoming() first. no this.new_incoming.");
		}

		if (this.incoming) {
			if (this.incoming.readyState != 4) {
				return;
			}

			meteor.dismantle(this.incoming);
		}

		if (this.operatimer) {
			clearTimeout(this.operatimer);
			delete this.operatimer;
		}

		xhr.onreadystatechange = UTIL.make_callback(this, this.incoming_state_change);
		xhr.onerror = UTIL.make_callback(this, this.incoming_on_error);
		meteor.debug("moved new incoming to incoming.");
		this.new_incoming = 0;
		this.incoming = xhr;
		this.incoming_state_change(xhr);

		// This code polls the xhr for new data in case opera is used. its necessary
		// because opera does not trigger an event if new data is available in state 3.
		if (window.opera) {
			this.operatimer = setInterval(UTIL.make_callback(this, this.incoming_state_change), 100);
			meteor.debug("timer: "+this.operatimer);
		}
	},
	init_state_change : function(xhr) { // fetch the client_id and go
		if (xhr.readyState == 4) {
			if (xhr.status == 200) {
				this.vars["id"] = xhr.responseText;
				meteor.debug("got client ID " + this.vars["id"]);

				meteor.dismantle(xhr);

				this.connect_new_incoming();
			} else if (xhr.status == 404) {
				this.error(xhr.responseText);
			} else {
				this.error(xhr.statusText);
			}
		}
	},
	/**
	 * Initialize the connection. This needs to be called before any data can be sent or received.
	 */
	init : function() { // fetch the client_id and go
		var xhr = new XMLHttpRequest();
		this.reconnect = 1;

		xhr.onreadystatechange = UTIL.make_callback(this, this.init_state_change);
		xhr.open("GET", UTIL.make_url(this.url, this.vars), true);
		xhr.send("");
	},
	/**
	 * Close incoming connection and clean up cyclic references.
	 */
	close : function() {
		var list = [this.new_incoming, this.incoming];
		for (var i = 0; i < list.length; i++) {
			var t = list[i];
			try {
				if (t) {
					meteor.dismantle(t);
				}
			} catch(e) { }
		}
		delete this.incoming;
		delete this.new_incoming;
		delete this.callback;
		delete this.error;
	},
	/**
	 * Send some data.
	 * @param {String} data String to be sent.
	 */
	send : function(data) {
		meteor.debug("sending "+data.length+" bytes");
		// check for status
		this.buffer += data;

		if (this.vars["id"]) {
		    if (!this.async) {
			this.write();
		    } else if (!this.will_write) {
			this.will_write = true;
			// we give a small window for more data coming in in the same loop
			window.setTimeout(UTIL.make_method(this, this.write), 20);
		    }
		}
	},
	outgoing_onerror : function(xhr) {
		meteor.debug("error while connecting outgoing. data lost, we should write back to buffer and retry.");
	},
	outgoing_state_change : function(xhr) {
		meteor.debug("outgoing state is "+xhr.readyState);

		if (xhr.readyState == 4) {
			xhr.onreadystatechange = null;
			if (xhr.status == 200) {
			    	// we do this do avoid opening too many connections. this should be enough
				this.will_write = false;
				if (this.buffer.length) window.setTimeout(UTIL.make_method(this, this.write), 20);
			} else  { // this basically means, that the server does not know the id
			    	this.error("It seems like the id timed out or something went wrong.");
			/* this should happen on timeout, but we dont have this right now
			} else { // we may retry here?
				this.error(xhr.statusText);
				this.buffer = this.old_buffer + this.buffer;
				// RETRY
				*/
			}
		}
	},
	write : function() {
		if (this.buffer.length == 0) return;

		var xhr = new XMLHttpRequest();

		/*
		if (this.outgoing) {
			// we could reuse the xhr object, however this
			// is not completely safe on safari/chrome
			// TODO: do it for firefox, opera, ie
			meteor.dismantle(this.outgoing);
		}
		*/

		xhr.open("POST", UTIL.make_url(this.url, this.vars), this.async);
		// we do this charset hackery because we have internal utf8 and plain ascii
		// for the rest of atom. this is supposed to be a binary transport
		if (this.async) {
		    xhr.onreadystatechange = UTIL.make_callback(this, this.outgoing_state_change);
		    xhr.onerror = UTIL.make_callback(this, this.outgoing_onerror);
		}

		//meteor.debug("outgoing state change is %o", xhr.onreadystatechange);
		if (xhr.sendAsBinary) {
			xhr.setRequestHeader("Content-Type", "application/octet-stream");
			xhr.setRequestHeader("Content-Length", this.buffer.length);
			xhr.sendAsBinary(this.buffer);
		} else {
			xhr.send(this.buffer);
		}
		meteor.debug("writing "+this.buffer.length+" bytes\n");
		this.old_buffer = this.buffer;
		this.buffer = "";
	}
};
// the params handed by the user could be prototyped with a
// msg and something more
meteor.CallbackWrapper = function(params, mapping) {
	this.mapping = mapping;
	this.params = params;
};
meteor.CallbackWrapper.prototype = {
	msg : function(p, message) {
		var ok = true;
		if ((this.params.source && this.params.source != p.source())
		||  (this.params.context && this.params.context != p.v("_context"))
		||  (this.params.target && this.params.target != p.target())
		) {
			ok = false;
			meteor.debug(p.toString()+" is not the one.\n");
		}

		if (ok) {
			if (this.params.object) {
				if (this.params.cb) {
					return this.params.cb.call(this.params.object, p, message, this);
				}

				return this.params.object.msg(p, message, this);
			} else {
				return this.params.cb(p, message, this);
			}
		}
	},
	active : function() {
		return this.mapping == 0 ? 0 : 1;
	},
	unregister : function() {
		if (this.mapping == 0) return;

		var list = this.mapping.get(this.params.method);

		for (var i = 0; i < list.length; i++) {
			if (list[i] == this) {
				list.splice(i, 1);
			}
		}

		this.mapping = 0;
	}
};
<commit_msg>timeout on outgoing connections and some more<commit_after>/*
Copyright (C) 2008-2009  Arne Goedeke

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.

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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
if( typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error( "This browser does not support XMLHttpRequest." )
};
/**
 * @namespace Meteor js connection namespace.
 */
meteor = new Object();
/**
 * Limit for the incoming buffer. When the incoming XMLHttpRequest object buffer grows larger than this, the connection is reinitiated.
 */
meteor.BUFFER_MAX = 1 << 16; // limit for incoming buffer, exceeding this buffer triggers a reconnect
meteor.dismantle = function(xhr) {
	delete xhr.onreadystatechange;
	delete xhr.onerror;
	if (xhr.readyState < 4) {
	    try { xhr.abort(); } catch (e) {};
	}
};
meteor.debug = function() {
	if (window.console && window.console.log) {
		if (window.console.firebug) {
			window.console.log.apply(window, arguments);
		} else { //this is IE
			window.console.log(arguments[0]);
		}
	}
};
/**
 * Meteor connection class. This is usually used with Atom serialization on top. Use psyc.Client if unsure.
 * @param {String} url URL of the Meteor connection endpoint.
 * @param {Function} callback Function to be called when data has been received.
 * @param {Function} error Function to be called when a fatal error occures.
 * @constructor
 * @example
 * var connection;
 * var incoming = function(data) {
 * 	document.write("Received data: " + data);
 * 	connection.send("Hello World.\n");
 * }
 * connection = new meteor.Connection("http://example.org/meteor/", incoming, alert);
 * connection.init();
 */
meteor.Connection = function(url, vars, callback, error) {
    this.url = url;
    this.vars = vars;
    this.buffer = "";
    this.callback = callback;
    this.error = error;
    this.async = true;
    this.pos = 0;
    this.reconnect = 1; // do a reconnect on close
};
meteor.Connection.prototype = {
	reconnect_incoming : function() {
		meteor.debug("reconnecting due to timeout.\n");
		if (this.new_incoming) {
			meteor.dismantle(this.new_incoming);
			delete this.new_incoming;
		}
		if (this.incoming) {
			meteor.dismantle(this.incoming);
			delete this.incoming;
		}
		this.connect_new_incoming();
	},
	new_incoming_state_change : function(xhr) {
		meteor.debug("new_incoming state is " + xhr.readyState);
		// we should check here for buffer length. maybe set a max
		// amount to shut down the main one ungracefully
		if (xhr.readyState >= 3) {
			this.connect_incoming();
		}
	},
	connect_new_incoming : function() {
		if (this.new_incoming) {
			// we already have one new incoming and are waiting for the
			// main one to shut down

			if (this.new_incoming.readyState == 4) {
			// someone is too fast for us.
			// TODO: we have to check for data in new_incoming,
			// not sure what to do with it. we can probably savely
			// parse it in case of atoms.
				meteor.debug("New connection already finished.\n");
			} else return this.connect_incoming();
		}

		meteor.debug("Connecting new incoming.\n");

		var xhr = new XMLHttpRequest();
		this.new_incoming = xhr;

		xhr.open("POST", UTIL.make_url(this.url, this.vars), true);
		// both opera and IE dont handle binary data correctly.
		if (!window.opera && navigator.appName != 'Microsoft Internet Explorer') {
			xhr.setRequestHeader("Content-Type", "application/octet-stream");
		}
		//xhr.overrideMimeType("text/plain; charset=ISO-8859-1");
		if (xhr.overrideMimeType) xhr.overrideMimeType('text/plain; charset=x-user-defined');
		xhr.onreadystatechange = UTIL.make_callback(this, this.new_incoming_state_change);
		xhr.send("");
	},
	set_nonblocking : function() {
		this.async = true;
	},
	set_blocking : function() {
		this.async = false;
	},
	incoming_state_change : function(xhr) {
		var s;

		if (xhr.readyState >= 3) {
			// workaround for IE
			try {
				s = xhr.status;
			} catch(e) {
				// this is ie country
				// this is ie
				meteor.debug("fucking ie");
			}

			if (s == 200) {
				var length = xhr.responseBody ? xhr.responseBody.length : xhr.responseText.length;

				if (length > this.pos) {
					meteor.debug((length-this.pos)+" bytes received in readyState "+xhr.readyState);
					var str;

					try {
						if (window.opera) {
							str = xhr.responseText.slice(this.pos);
						} else if (xhr.responseBody) {
							str = xhr.responseBody.join("");
						} else {
							str = xhr.responseText.slice(this.pos);
							var t = str.split("");
							for (var i = 0; i < str.length; i++) {
								t[i] = t[i].charCodeAt(0) & 0xff;
							}
							str = String.fromCharCode.apply(window, t);
						}

						meteor.debug("calling callback: %o with %db of data", this.callback, str.length);
						this.callback(str);
					} catch (error) {
						meteor.debug("ERROR: "+error);
					}

					this.pos = length;
				}

				if (xhr.readyState == 4 || this.pos >= meteor.BUFFER_MAX) {
					if (this.operatimer) {
						clearTimeout(this.operatimer);
						delete this.operatimer;
					}
					if (this.reconnect) this.connect_new_incoming();
				}
			} else {
			// this throws an exception in firefox. brain
			//	con.error(this.statusText);
			}
		}
	},
	incoming_on_error : function() {
		meteor.debug("INCOMING ERROR!");
		window.setTimeout(UTIL.make_callback(this, this.connect_new_incoming), 500);
	},
	connect_incoming : function(xhr) {
		if (!xhr) {
			if (this.new_incoming) {
				xhr = this.new_incoming;
			} else throw("you need to call new_incoming() first. no this.new_incoming.");
		}

		if (this.incoming) {
		    	if (this.incoming.readyState != 4) {
			    // we lost some data here. we will still connect the new one because we dont expect it
			    // to be closed properly. we need to implement _id in order to fix this properly.
			    meteor.debug("Lost data on incoming connection (probably).");
			}
			meteor.dismantle(this.incoming);
		}

		if (this.operatimer) {
			clearTimeout(this.operatimer);
			delete this.operatimer;
		}

		xhr.onreadystatechange = UTIL.make_callback(this, this.incoming_state_change);
		xhr.onerror = UTIL.make_callback(this, this.incoming_on_error);
		meteor.debug("moved new incoming to incoming.");
		this.new_incoming = 0;
		this.incoming = xhr;
		this.incoming_state_change(xhr);

		// This code polls the xhr for new data in case opera is used. its necessary
		// because opera does not trigger an event if new data is available in state 3.
		if (window.opera) {
			this.operatimer = setInterval(UTIL.make_callback(this, this.incoming_state_change), 100);
			meteor.debug("timer: "+this.operatimer);
		}
	},
	init_state_change : function(xhr) { // fetch the client_id and go
		if (xhr.readyState == 4) {
			if (xhr.status == 200) {
				this.vars["id"] = xhr.responseText;
				meteor.debug("got client ID " + this.vars["id"]);

				meteor.dismantle(xhr);

				this.connect_new_incoming();
			} else if (xhr.status == 404) {
				this.error(xhr.responseText);
			} else {
				this.error(xhr.statusText);
			}
		}
	},
	/**
	 * Initialize the connection. This needs to be called before any data can be sent or received.
	 */
	init : function() { // fetch the client_id and go
		var xhr = new XMLHttpRequest();
		this.reconnect = 1;

		xhr.onreadystatechange = UTIL.make_callback(this, this.init_state_change);
		xhr.open("GET", UTIL.make_url(this.url, this.vars), true);
		xhr.send("");
	},
	/**
	 * Close incoming connection and clean up cyclic references.
	 */
	close : function() {
		var list = [this.new_incoming, this.incoming, this.outgoing];
		for (var i = 0; i < list.length; i++) {
			var t = list[i];
			try {
				if (t) {
					meteor.dismantle(t);
				}
			} catch(e) { }
		}
		delete this.outgoing;
		delete this.incoming;
		delete this.new_incoming;
		delete this.callback;
		delete this.error;
	},
	/**
	 * Send some data.
	 * @param {String} data String to be sent.
	 */
	send : function(data) {
		meteor.debug("sending "+data.length+" bytes");
		// check for status
		this.buffer += data;

		if (this.vars["id"]) {
		    if (!this.async) {
			this.write();
		    } else if (!this.will_write) {
			this.will_write = true;
			// we give a small window for more data coming in in the same loop
			window.setTimeout(UTIL.make_method(this, this.write), 20);
		    }
		}
	},
	outgoing_onerror : function(xhr) {
		this.will_write = false;
		this.buffer = this.old_buffer + this.buffer;
		this.write();
	},
	outgoing_state_change : function(xhr) {
		meteor.debug("outgoing state is "+xhr.readyState);

		if (xhr.readyState == 4) {
		    	window.clearTimeout(this.outgoing_timeout);
			xhr.onreadystatechange = null;
			if (xhr.status == 200) {
			    	// we do this do avoid opening too many connections. this should be enough
				this.will_write = false;
				if (this.buffer.length) window.setTimeout(UTIL.make_method(this, this.write), 20);
			} else  { // this basically means, that the server does not know the id
			    	this.error("It seems like the id timed out or something went wrong: "+xhr.statusText);
			}
			delete this.outdoing;
			meteor.dismantle(xhr);
		}
	},
	write : function() {
		if (this.buffer.length == 0) return;

		var xhr = new XMLHttpRequest();
		this.outgoing = xhr; // we keep it to be able to clean up

		/*
		if (this.outgoing) {
			// we could reuse the xhr object, however this
			// is not completely safe on safari/chrome
			// TODO: do it for firefox, opera, ie
			meteor.dismantle(this.outgoing);
		}
		*/

		xhr.open("POST", UTIL.make_url(this.url, this.vars), this.async);
		// we do this charset hackery because we have internal utf8 and plain ascii
		// for the rest of atom. this is supposed to be a binary transport
		if (this.async) {
		    meteor.debug("doing async request. setting callbacks");
		    xhr.onreadystatechange = UTIL.make_callback(this, this.outgoing_state_change);
		    xhr.onerror = UTIL.make_callback(this, this.outgoing_onerror);
		    var cb = UTIL.make_method(this, function() {
			meteor.dismantle(xhr);
			delete this.outgoing;
			this.will_write = false;
			this.buffer = this.old_buffer + this.buffer;
			this.write();
		    });
		    this.outgoing_timeout = window.setTimeout(cb, 3000);
		} else meteor.debug("doing sync request.");

		//meteor.debug("outgoing state change is %o", xhr.onreadystatechange);
		if (xhr.sendAsBinary) {
			xhr.setRequestHeader("Content-Type", "application/octet-stream");
			xhr.setRequestHeader("Content-Length", this.buffer.length);
			xhr.sendAsBinary(this.buffer);
		} else {
			xhr.send(this.buffer);
		}
		meteor.debug("writing "+this.buffer.length+" bytes\n");
		this.old_buffer = this.buffer;
		this.buffer = "";
	}
};
// the params handed by the user could be prototyped with a
// msg and something more
meteor.CallbackWrapper = function(params, mapping) {
	this.mapping = mapping;
	this.params = params;
};
meteor.CallbackWrapper.prototype = {
	msg : function(p, message) {
		var ok = true;
		if ((this.params.source && this.params.source != p.source())
		||  (this.params.context && this.params.context != p.v("_context"))
		||  (this.params.target && this.params.target != p.target())
		) {
			ok = false;
			meteor.debug(p.toString()+" is not the one.\n");
		}

		if (ok) {
			if (this.params.object) {
				if (this.params.cb) {
					return this.params.cb.call(this.params.object, p, message, this);
				}

				return this.params.object.msg(p, message, this);
			} else {
				return this.params.cb(p, message, this);
			}
		}
	},
	active : function() {
		return this.mapping == 0 ? 0 : 1;
	},
	unregister : function() {
		if (this.mapping == 0) return;

		var list = this.mapping.get(this.params.method);

		for (var i = 0; i < list.length; i++) {
			if (list[i] == this) {
				list.splice(i, 1);
			}
		}

		this.mapping = 0;
	}
};
<|endoftext|>


<commit_before>import React from 'react';
import { Provider } from 'react-redux';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';

import App from './components/app';
import reducers from './reducers';

import Bootstrap from '../node_modules/bootstrap/dist/css/bootstrap.css';
import FontAwesome from '../node_modules/font-awesome/css/font-awesome.css';
import styling from '../css/app.scss';

ReactDOM.render(
  <Provider store={createStore(reducers)}>
    <App />
  </Provider>
    , document.getElementById('container'));
<commit_msg>Added Bootstrap,FontAwesome and removed comments<commit_after>import React from 'react';
import { Provider } from 'react-redux';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';

import App from './components/app';
import reducers from './reducers';

import Bootstrap from '../node_modules/bootstrap/dist/css/bootstrap.css';
import FontAwesome from '../node_modules/font-awesome/css/font-awesome.css';
import Styling from '../css/app.scss';

ReactDOM.render(
  <Provider store={createStore(reducers)}>
    <App />
  </Provider>
    , document.getElementById('container'));
<|endoftext|>


<commit_before>/**
 * @namespace
 */
var Cache = function () {
    /**
     * Default values
     */
    var DEFAULT = {
        prefix: '_cache',
        ttl: 604800,
        provider: 'localStorage'
    };

    var eventSubscribers  = {
        cacheAdded: [],
        cacheRemoved: []
    };

    /**
     * Group all functions that are shared across all providers
     */
    var _this = {

        getProvider: function (name) {
            switch (name) {
            case 'localStorage':
               return localStorageProvider;
            case 'array':
                return arrayProvider;
            }
        },
        /**
         * Accept keys as array e.g: {blogId:"2",action:"view"} and convert it to unique string
         */
        generateKey: function (object) {
            var generatedKey = DEFAULT.prefix + '_',
                keyArray = [];

            for (var key in object){
                if(object.hasOwnProperty(key))
                {
                    keyArray.push(key);
                }
            }

            keyArray.sort();
            for(var i=0; i<keyArray.length; i++){
                generatedKey += keyArray[i] + '_' + object[keyArray[i]];
                if(i !== (keyArray.length - 1)){
                    generatedKey += '__';
                }
            }
            return generatedKey;
        },
        generateContextKey: function(key,value){
            return DEFAULT.prefix + '_context_' + key + '_' + value;
        },
        /**
         * Get current time (compared to Epoch time) in seconds
         */
        getCurrentTime: function(){
            var timestamp = new Date().getTime();
            return Math.floor(timestamp/1000);
        },
        /**
         * Return default values
         */
        getDefault: function(){
            return DEFAULT;
        },
        /**
         * Return subscribers
         *
         * @returns {{cacheAdded: Array, cacheRemoved: Array}}
         */
        getEventSubscribers: function(){
            return eventSubscribers;
        },
        /**
         * Dispatch event to subscribers
         *
         * @param event Event name
         * @param object Object will be sent to subscriber
         */
        dispatchEvent: function(event, object){
            var callbacks = eventSubscribers[event];
            if(callbacks.length < 1){
                return;
            }
            for(var index = 0; index < callbacks.length; index++){
                if(typeof(callbacks[index]) !== 'undefined' && _this.isFunction(callbacks[index])){
                    callbacks[index](object);
                }
            }
        },
        /**
         * Check if x is a function
         *
         * @param x
         * @returns {boolean}
         */
        isFunction: function(x){
        return Object.prototype.toString.call(x) == '[object Function]';
        }
    };

    /**
     * Initiate providers as local variables
     */
    var localStorageProvider = new LocalStorageProvider(_this),
        arrayProvider = new ArrayProvider(_this);

    /**
     * Public functions
     */
    return {
        /**
         * @method Cache.use
         * @description Switch provider. available providers are: 'localStorage','array'
         *
         * @param provider
         */
        use: function(provider) {
            DEFAULT.provider = provider;
            return this;
        },
        /**
         * @method Cache.get
         * @description Get cache by array key
         *
         * @param key - Array key
         * @returns {string}
         * @example
         * Cache.get({blogId:"2",action:"view"});
         */
        get: function(key){
            return _this.getProvider(DEFAULT.provider).get(key);
        },
        /**
         * @method Cache.set
         * @description Save data for key
         *
         * @param key - Array key
         * @param value - value must be a string
         * @param ttl - Time to live in seconds
         * @param contexts - Contexts
         * @returns {Cache}
         */
        set: function(key, value, ttl, contexts){
            _this.getProvider(DEFAULT.provider).set(key, value, ttl, contexts);
            return this;
        },
        /**
         * @method Cache.setPrefix
         * @description Set prefix for cache key (default: _cache)
         *
         * @param prefix
         * @returns {Cache}
         */
        setPrefix: function(prefix){
            DEFAULT.prefix = prefix;
            return this;
        },
        /**
         * @method Cache.getPrefix
         * @description Get prefix for cache key
         *
         * @returns {string}
         */
        getPrefix: function(){
            return DEFAULT.prefix;
        },
        /**
         * @method Cache.removeByKey
         *
         * @param key
         * @returns {Cache}
         */
        removeByKey: function(key){
            _this.getProvider(DEFAULT.provider).removeByKey(key);
            return this;
        },
        /**
         * @method Cache.removeByContext
         *
         * @param context
         * @returns {Cache}
         */
        removeByContext: function(context){
            _this.getProvider(DEFAULT.provider).removeByContext(context);
            return this;
        },
        /**
         * @method Cache.on
         * @description Subscribe to an event
         *
         * @param event
         * @param callback
         */
        on: function(event, callback){
            eventSubscribers[event].push(callback);
        },
        /**
         * @method Cache.unsubscribe
         * @description Unsubscribe to an event
         *
         * @param event
         * @param callback
         */
        unsubscribe: function(event, callback){
            var callbacks = eventSubscribers[event];
            for(var i = 0; i < callbacks.length; i++){
                if(callbacks[i] === callback){
                    delete callbacks[i];
                    break;
                }
            }
        }

    };
};

<commit_msg>Fix indentation<commit_after>/**
 * @namespace
 */
var Cache = function () {
    /**
     * Default values
     */
    var DEFAULT = {
        prefix: '_cache',
        ttl: 604800,
        provider: 'localStorage'
    };

    var eventSubscribers  = {
        cacheAdded: [],
        cacheRemoved: []
    };

    /**
     * Group all functions that are shared across all providers
     */
    var _this = {

        getProvider: function (name) {
            switch (name) {
            case 'localStorage':
               return localStorageProvider;
            case 'array':
                return arrayProvider;
            }
        },
        /**
         * Accept keys as array e.g: {blogId:"2",action:"view"} and convert it to unique string
         */
        generateKey: function (object) {
            var generatedKey = DEFAULT.prefix + '_',
                keyArray = [];

            for (var key in object){
                if(object.hasOwnProperty(key))
                {
                    keyArray.push(key);
                }
            }

            keyArray.sort();
            for(var i=0; i<keyArray.length; i++){
                generatedKey += keyArray[i] + '_' + object[keyArray[i]];
                if(i !== (keyArray.length - 1)){
                    generatedKey += '__';
                }
            }
            return generatedKey;
        },
        generateContextKey: function(key,value){
            return DEFAULT.prefix + '_context_' + key + '_' + value;
        },
        /**
         * Get current time (compared to Epoch time) in seconds
         */
        getCurrentTime: function(){
            var timestamp = new Date().getTime();
            return Math.floor(timestamp/1000);
        },
        /**
         * Return default values
         */
        getDefault: function(){
            return DEFAULT;
        },
        /**
         * Return subscribers
         *
         * @returns {{cacheAdded: Array, cacheRemoved: Array}}
         */
        getEventSubscribers: function(){
            return eventSubscribers;
        },
        /**
         * Dispatch event to subscribers
         *
         * @param event Event name
         * @param object Object will be sent to subscriber
         */
        dispatchEvent: function(event, object){
            var callbacks = eventSubscribers[event];
            if(callbacks.length < 1){
                return;
            }
            for(var index = 0; index < callbacks.length; index++){
                if(typeof(callbacks[index]) !== 'undefined' && _this.isFunction(callbacks[index])){
                    callbacks[index](object);
                }
            }
        },
        /**
         * Check if x is a function
         *
         * @param x
         * @returns {boolean}
         */
        isFunction: function(x){
            return Object.prototype.toString.call(x) == '[object Function]';
        }
    };

    /**
     * Initiate providers as local variables
     */
    var localStorageProvider = new LocalStorageProvider(_this),
        arrayProvider = new ArrayProvider(_this);

    /**
     * Public functions
     */
    return {
        /**
         * @method Cache.use
         * @description Switch provider. available providers are: 'localStorage','array'
         *
         * @param provider
         */
        use: function(provider) {
            DEFAULT.provider = provider;
            return this;
        },
        /**
         * @method Cache.get
         * @description Get cache by array key
         *
         * @param key - Array key
         * @returns {string}
         * @example
         * Cache.get({blogId:"2",action:"view"});
         */
        get: function(key){
            return _this.getProvider(DEFAULT.provider).get(key);
        },
        /**
         * @method Cache.set
         * @description Save data for key
         *
         * @param key - Array key
         * @param value - value must be a string
         * @param ttl - Time to live in seconds
         * @param contexts - Contexts
         * @returns {Cache}
         */
        set: function(key, value, ttl, contexts){
            _this.getProvider(DEFAULT.provider).set(key, value, ttl, contexts);
            return this;
        },
        /**
         * @method Cache.setPrefix
         * @description Set prefix for cache key (default: _cache)
         *
         * @param prefix
         * @returns {Cache}
         */
        setPrefix: function(prefix){
            DEFAULT.prefix = prefix;
            return this;
        },
        /**
         * @method Cache.getPrefix
         * @description Get prefix for cache key
         *
         * @returns {string}
         */
        getPrefix: function(){
            return DEFAULT.prefix;
        },
        /**
         * @method Cache.removeByKey
         *
         * @param key
         * @returns {Cache}
         */
        removeByKey: function(key){
            _this.getProvider(DEFAULT.provider).removeByKey(key);
            return this;
        },
        /**
         * @method Cache.removeByContext
         *
         * @param context
         * @returns {Cache}
         */
        removeByContext: function(context){
            _this.getProvider(DEFAULT.provider).removeByContext(context);
            return this;
        },
        /**
         * @method Cache.on
         * @description Subscribe to an event
         *
         * @param event
         * @param callback
         */
        on: function(event, callback){
            eventSubscribers[event].push(callback);
        },
        /**
         * @method Cache.unsubscribe
         * @description Unsubscribe to an event
         *
         * @param event
         * @param callback
         */
        unsubscribe: function(event, callback){
            var callbacks = eventSubscribers[event];
            for(var i = 0; i < callbacks.length; i++){
                if(callbacks[i] === callback){
                    delete callbacks[i];
                    break;
                }
            }
        }

    };
};

<|endoftext|>


<commit_before>var combine = require('./jsCombine'),
    fs = require('fs'),
    templateUtil = require('./templateUtil'),
    watch = require('./watcher.js');

function logError(err) {
    console.error(err.stack);
}

function loadConfig(path) {
    return JSON.parse(fs.readFileSync(path, 'utf8'));
}
function loadList(config) {
    var moduleList = [];
    for (var name in config.modules) {
        moduleList.push(name);
    }
    return moduleList;
}
function explodeViews(module, config) {
    var views = config.views,
        loadedTemplates = {},
        ret = [],

        files = module.controller ? module.support : module;

    for (var i = 0, len = files.length; i < len; i++) {
        var resource = files[i];
        if (resource === 'module_map.json') {
            var buildModuleMap = function(callback) {
                var map = {};
                for (var name in config.modules) {
                    var module = config.modules[name];
                    if (module.routes) {
                        for (var route in module.routes) {
                            map[route] = name;
                        }
                    }
                }

                templateUtil.loadModuleMap(map, config.moduleMap, callback);
            };
            buildModuleMap.sourceFile = 'module_map.json';

            ret.push(buildModuleMap);
        } else {
            ret.push(resource);
        }

        if (views[resource]) {
            views[resource].forEach(function(template) {
                var generator = function(callback) {
                    templateUtil.loadTemplate(template, config.templateCache, callback);
                };
                generator.sourceFile = template;
                ret.push(generator);
            });
        }
    }

    // Generate the controller if we have the info for it
    if (module.controller) {
      var controllerGen = function(callback) {
        templateUtil.loadController(module.controller, module.routes, callback);
      };
      controllerGen.sourceFile = module.controller;
      ret.push(controllerGen);
    }

    return ret;
}

exports.init = function(configFile, outdir) {
    var config = loadConfig(configFile),
        moduleList = loadList(config);

    return {
        build: function(moduleName, callback) {
            var modules = moduleName ? [moduleName] : moduleList;
            modules.forEach(function(name) {
                var resources = explodeViews(config.modules[name], config),
                    moduleName = outdir + '/' + name + '.js';
                combine.combine(resources, moduleName, function(err, data) {
                    if (err) {
                        fs.unlink(moduleName);
                    }

                    callback(err, data)
                });
            });
        },
        watch: function(moduleName, callback) {
            var modules = moduleName ? [moduleName] : moduleList,
                self = this;

            // Watch for changes in the config file
            // WARN : This isn't really safe for multiple executions, this is a concious design decision
            watch.watchFile(configFile, [], function() {
                // Reload our config
                config = loadConfig(configFile);
                moduleList = loadList(config);

                // Cleanup what we can, breaking things along the way
                watch.unwatchAll();
                self.watch(moduleName, callback);
            });

            // Watch the individual components
            modules.forEach(function(name) {
                self.build(name, function(err, status) {
                    if (err) {
                        throw err;
                    }

                    callback(err, status);

                    if (status.fileName === 'module_map.json') {
                        return;
                    }
                    watch.watchFile("foo" + status.fileName + "foo", status.input, function() {
                        self.build(name, callback);
                    });
                });
            });
        }
    };
};
<commit_msg>Do not fail if there are billy.json parser errors.<commit_after>var combine = require('./jsCombine'),
    fs = require('fs'),
    templateUtil = require('./templateUtil'),
    watch = require('./watcher.js');

function logError(err) {
    console.error(err.stack);
}

function loadConfig(path) {
    var config = fs.readFileSync(path, 'utf8');

    try {
        return JSON.parse(config);
    } catch (err) {
        // Do not die a horrible death if this is just a syntax error
        logError(err);
        return {};
    }
}
function loadList(config) {
    var moduleList = [];
    for (var name in config.modules) {
        moduleList.push(name);
    }
    return moduleList;
}
function explodeViews(module, config) {
    var views = config.views,
        loadedTemplates = {},
        ret = [],

        files = module.controller ? module.support : module;

    for (var i = 0, len = files.length; i < len; i++) {
        var resource = files[i];
        if (resource === 'module_map.json') {
            var buildModuleMap = function(callback) {
                var map = {};
                for (var name in config.modules) {
                    var module = config.modules[name];
                    if (module.routes) {
                        for (var route in module.routes) {
                            map[route] = name;
                        }
                    }
                }

                templateUtil.loadModuleMap(map, config.moduleMap, callback);
            };
            buildModuleMap.sourceFile = 'module_map.json';

            ret.push(buildModuleMap);
        } else {
            ret.push(resource);
        }

        if (views[resource]) {
            views[resource].forEach(function(template) {
                var generator = function(callback) {
                    templateUtil.loadTemplate(template, config.templateCache, callback);
                };
                generator.sourceFile = template;
                ret.push(generator);
            });
        }
    }

    // Generate the controller if we have the info for it
    if (module.controller) {
      var controllerGen = function(callback) {
        templateUtil.loadController(module.controller, module.routes, callback);
      };
      controllerGen.sourceFile = module.controller;
      ret.push(controllerGen);
    }

    return ret;
}

exports.init = function(configFile, outdir) {
    var config = loadConfig(configFile),
        moduleList = loadList(config);

    return {
        build: function(moduleName, callback) {
            var modules = moduleName ? [moduleName] : moduleList;
            modules.forEach(function(name) {
                var resources = explodeViews(config.modules[name], config),
                    moduleName = outdir + '/' + name + '.js';
                combine.combine(resources, moduleName, function(err, data) {
                    if (err) {
                        fs.unlink(moduleName);
                    }

                    callback(err, data)
                });
            });
        },
        watch: function(moduleName, callback) {
            var modules = moduleName ? [moduleName] : moduleList,
                self = this;

            // Watch for changes in the config file
            // WARN : This isn't really safe for multiple executions, this is a concious design decision
            watch.watchFile(configFile, [], function() {
                // Reload our config
                config = loadConfig(configFile);
                moduleList = loadList(config);

                // Cleanup what we can, breaking things along the way
                watch.unwatchAll();
                self.watch(moduleName, callback);
            });

            // Watch the individual components
            modules.forEach(function(name) {
                self.build(name, function(err, status) {
                    if (err) {
                        throw err;
                    }

                    callback(err, status);

                    if (status.fileName === 'module_map.json') {
                        return;
                    }
                    watch.watchFile("foo" + status.fileName + "foo", status.input, function() {
                        self.build(name, callback);
                    });
                });
            });
        }
    };
};
<|endoftext|>


<commit_before>/**
 * @fileoverview
 * Classes related to defining settings for views. Settings are dict-like
 * objects, providing get/set/exists methods. Settings are persisted by
 * calling out to the global storage ogject
 *
 * @see storage
 */

/**
 * @constructor
 */
var SettingsBase = function()
{
  /**
   * Update the view according to the new value of the setting key.
   * @private
   */
  var syncView = function(key, value)
  {
    var
    switches = document.getElementsByTagName('toolbar-switches'),
    _switch = null,
    butttons = null,
    button = null,
    i = 0,
    j = 0,
    key_id = this.view_id + '.' + key,
    force_reflow = false;

    for( ; _switch = switches[i]; i++)
    {
      force_reflow = false;
      buttons = _switch.getElementsByTagName('button');
      for( j = 0; button = buttons[j]; j++)
      {
        if( button.getAttribute('key') == key_id )
        {
          button.setAttribute('is-active' , value ? "true" : "false" );
          force_reflow = true;
        }
      }
      if( force_reflow )
      {
        _switch.innerHTML += "";
      }
    }
  }

  /**
   * Set the value of key.
   */
  this.set = function(key, value, sync_switches)
  {
    window.localStorage.setItem(key, JSON.stringify(this.map[key] = value))
    if( sync_switches && typeof value == 'boolean' )
    {
      syncView(key, value);
    }
  }

  /**
   * Returns the value assosciated with "key". If the key does not exist,
   * returns undefined
   * @argument {string} key whos value to get
   */
  this.get = function(key)
  {
    return (
      this.map[key] ||
      (this.map[key] = JSON.parse(window.localStorage.getItem(key) || null))
    );
  }

  /**
   * Check if a particular key exist in the settings object
   */
  this.exists = function(key)
  {
    return key in this.map;
  }

  this.init = function(view_id, key_map, label_map, setting_map, templates)
  {
    this.map = {};
    this.view_id = view_id;
    this.label_map = label_map;
    this.setting_map = setting_map;
    this.templates = templates || {};
    var stored_map = key_map, key = '', val = '';
    for( key in stored_map)
    {
      val = window.localStorage.getItem(key);
      this.map[key] = (val === undefined || val === null) ? key_map[key] : JSON.parse(val);
    }
    if(!window.settings)
    {
      window.settings = {};
    }
    window.settings[arguments[0]] = this;
  }

  if(!window.localStorage)
  {
    window.localStorage =
    {
      setItem: function(name, value)
      {
        document.cookie = name + "="+
          encodeURIComponent(value)+
          "; expires="+(new Date(new Date().getTime()+ (360 * 24 * 60 * 60 * 1000 ))).toGMTString()+
          "; path=/";
      },
      getItem: function(name)
      {
        var match = null;
        if (match = new RegExp(name+'\=([^;]*);','').exec(document.cookie+';'))
        {
          return decodeURIComponent(match[1]);
        }
        return null;
      }
    }
  }
}

/**
 * @constructor
 * @extends SettingsBase
 */
var Settings = function(view_id, key_map, label_map, setting_map, template)
{
  this.init(view_id, key_map, label_map, setting_map, template);
}

Settings.get_setting_with_view_key_token = function(token)
{
  var arr = token.split('.'), setting = window.settings[arr[0]], key = arr[1];
  return setting && setting.exists(key) && {
      setting: setting,
      view: arr[0],
      key: key,
      value: setting.get(key),
      label: setting.label_map[key]
    } || null;
}

Settings.prototype = new SettingsBase();

<commit_msg>fixed issue with returning null and JSON.parse in settings<commit_after>/**
 * @fileoverview
 * Classes related to defining settings for views. Settings are dict-like
 * objects, providing get/set/exists methods. Settings are persisted by
 * calling out to the global storage ogject
 *
 * @see storage
 */

/**
 * @constructor
 */
var SettingsBase = function()
{
  /**
   * Update the view according to the new value of the setting key.
   * @private
   */
  var syncView = function(key, value)
  {
    var
    switches = document.getElementsByTagName('toolbar-switches'),
    _switch = null,
    butttons = null,
    button = null,
    i = 0,
    j = 0,
    key_id = this.view_id + '.' + key,
    force_reflow = false;

    for( ; _switch = switches[i]; i++)
    {
      force_reflow = false;
      buttons = _switch.getElementsByTagName('button');
      for( j = 0; button = buttons[j]; j++)
      {
        if( button.getAttribute('key') == key_id )
        {
          button.setAttribute('is-active' , value ? "true" : "false" );
          force_reflow = true;
        }
      }
      if( force_reflow )
      {
        _switch.innerHTML += "";
      }
    }
  }

  /**
   * Set the value of key.
   */
  this.set = function(key, value, sync_switches)
  {
    window.localStorage.setItem(key, JSON.stringify(this.map[key] = value))
    if( sync_switches && typeof value == 'boolean' )
    {
      syncView(key, value);
    }
  }

  /**
   * Returns the value assosciated with "key". If the key does not exist,
   * returns undefined
   * @argument {string} key whos value to get
   */
  this.get = function(key)
  {
    var val = "";
    return (
      this.map[key] ||
      (this.map[key] = ((val = window.localStorage.getItem(key)) && JSON.parse(val) || null))
    );
  }

  /**
   * Check if a particular key exist in the settings object
   */
  this.exists = function(key)
  {
    return key in this.map;
  }

  this.init = function(view_id, key_map, label_map, setting_map, templates)
  {
    this.map = {};
    this.view_id = view_id;
    this.label_map = label_map;
    this.setting_map = setting_map;
    this.templates = templates || {};
    var stored_map = key_map, key = '', val = '';
    for( key in stored_map)
    {
      val = window.localStorage.getItem(key);
      this.map[key] = (val === undefined || val === null) ? key_map[key] : JSON.parse(val);
    }
    if(!window.settings)
    {
      window.settings = {};
    }
    window.settings[arguments[0]] = this;
  }

  if(!window.localStorage)
  {
    window.localStorage =
    {
      setItem: function(name, value)
      {
        document.cookie = name + "="+
          encodeURIComponent(value)+
          "; expires="+(new Date(new Date().getTime()+ (360 * 24 * 60 * 60 * 1000 ))).toGMTString()+
          "; path=/";
      },
      getItem: function(name)
      {
        var match = null;
        if (match = new RegExp(name+'\=([^;]*);','').exec(document.cookie+';'))
        {
          return decodeURIComponent(match[1]);
        }
        return null;
      }
    }
  }
}

/**
 * @constructor
 * @extends SettingsBase
 */
var Settings = function(view_id, key_map, label_map, setting_map, template)
{
  this.init(view_id, key_map, label_map, setting_map, template);
}

Settings.get_setting_with_view_key_token = function(token)
{
  var arr = token.split('.'), setting = window.settings[arr[0]], key = arr[1];
  return setting && setting.exists(key) && {
      setting: setting,
      view: arr[0],
      key: key,
      value: setting.get(key),
      label: setting.label_map[key]
    } || null;
}

Settings.prototype = new SettingsBase();

<|endoftext|>


<commit_before>"use strict";

const gulp  = require('gulp');
const babel = require('gulp-babel');
const del = require('del');

const srcFiles = ['index.js', 'code/**/*.js'];

const watchOpts = {
	debounceDelay: 2000
};

gulp.task('clean', () => {
	return del(['./build']);
});

gulp.task('src', () => {
	gulp.src(['index.js'])
		.pipe(babel())
		.pipe(gulp.dest('./build'));

	gulp.src('code/**/*.js')
		.pipe(babel())
		.pipe(gulp.dest('./build/code'));

	gulp.watch(srcFiles, watchOpts, ['src']);
});

// 'code/**/*.js'

gulp.task('defs', () => {
	gulp.src('./defs/*.json5')
		.pipe(gulp.dest('./build/defs'));

	gulp.watch('./defs/*.json5', watchOpts, ['defs']);
});

gulp.task('infra', () => {
	gulp.src('./package.json')
		.pipe(gulp.dest('./build'));

	gulp.watch('./package.json', watchOpts, ['infra']);
});

gulp.task('default', ['src','defs','infra',], () => {
});
<commit_msg>Added release build which creates the build directory with the committed samples only.<commit_after>"use strict";

const gulp     = require('gulp');
const babel    = require('gulp-babel');
const del      = require('del').sync;
const execSync = require('child_process').execSync;

const srcFiles = ['index.js', 'code/**/*.js'];

const watchOpts = {
	debounceDelay: 2000
};

gulp.task('clean', () => {
	return del(['./build']);
});

gulp.task('src', () => {
	gulp.src(['index.js'])
		.pipe(babel())
		.pipe(gulp.dest('./build'));

	gulp.src('code/**/*.js')
		.pipe(babel())
		.pipe(gulp.dest('./build/code'));
});

gulp.task('defs', () => {
	del(['./build/defs']);
	gulp.src('./defs/*.json5')
		.pipe(gulp.dest('./build/defs'));

});

gulp.task('samples', () => {
	del(['./build/defs']);

	let output = execSync('git ls-files defs', { encoding: 'utf8' }),
		files  = output
			.trim()
			.split("\n");

	gulp.src(files)
		.pipe(gulp.dest('./build/defs'));

});

gulp.task('infra', () => {
	gulp.src('./package.json')
		.pipe(gulp.dest('./build'));
});

gulp.task('default', ['src', 'defs', 'infra',], () => {
	gulp.watch(srcFiles, watchOpts, ['src']);
	gulp.watch('./defs/*.json5', watchOpts, ['defs']);
	gulp.watch('./package.json', watchOpts, ['infra']);
});

gulp.task('release', ['src', 'samples', 'infra'], () => {

});
<|endoftext|>


<commit_before>// ID of the (hidden) form field used to store the JSON representation of the
// object being edited in this page
var sJsonFieldId = 'json_object';

// The memory representation of the object
var oObj = {};

// Mapping between the fields of the form and the attribute of the current object
// If aFieldsMap[2] contains 'foo' it means that oObj.foo corresponds to the field
// of Id 'att_2' in the form
var aFieldsMap = new Array;

// Update the whole object from the form and also update its
// JSON (serialized) representation in the (hidden) field
function UpdateObjectFromForm(aFieldsMap, oObj)
{
	for(i=0; i<aFieldsMap.length; i++)
	{
		var oElement = document.getElementById('att_'+i);
		var sFieldName = aFieldsMap[i];
		oObj['m_aCurrValues'][sFieldName] = oElement.value;
		sJSON = JSON.stringify(oObj);
		var oJSON = document.getElementById(sJsonFieldId);
		oJSON.value = sJSON;
	}
	return oObj;
}

// Update the specified field from the current object
function UpdateFieldFromObject(idField, aFieldsMap, oObj)
{
	var oElement = document.getElementById('att_'+idField);
	oElement.value = oObj['m_aCurrValues'][aFieldsMap[idField]];
}
// Update all the fields of the Form from the current object
function UpdateFormFromObject(aFieldsMap, oObj)
{
	for(i=0; i<aFieldsMap.length; i++)
	{
		UpdateFieldFromForm(i, aFieldsMap, oObj);
	}
}

// This function is meant to be called from the AJAX page
// It reloads the object (oObj) from the JSON representation
// and also updates the form field that contains the JSON
// representation of the object
function ReloadObjectFromServer(sJSON)
{
	//console.log('JSON value:', sJSON);
	var oJSON = document.getElementById(sJsonFieldId);
	oJSON.value = sJSON;
	oObj = JSON.parse( '(' + sJSON + ')' );
	return oObj;
}

function GoToStep(iCurrentStep, iNextStep)
{
	var oCurrentStep = document.getElementById('wizStep'+iCurrentStep);
	if (iNextStep > iCurrentStep)
	{
		// Check the values when moving forward
		if (CheckFields('wizStep'+iCurrentStep))
		{
			oCurrentStep.style.display = 'none';
			ActivateStep(iNextStep);
		}
	}
	else
	{
		oCurrentStep.style.display = 'none';
		ActivateStep(iNextStep);
	}
}

function ActivateStep(iTargetStep)
{
	UpdateObjectFromForm(aFieldsMap, oObj);
	var oNextStep = document.getElementById('wizStep'+(iTargetStep));
	window.location.href='#step'+iTargetStep;
	// If a handler for entering this step exists, call it
	if (typeof(this['OnEnterStep'+iTargetStep]) == 'function')
	{
		eval( 'OnEnterStep'+iTargetStep+'();');
	}
	oNextStep.style.display = '';
	G_iCurrentStep = iTargetStep;
	//$('#wizStep'+(iTargetStep)).block({ message: null });
}

//function AjaxGetValuesDef(oObj, sClass, sAttCode, iFieldId)
//{
//	var oJSON = document.getElementById(sJsonFieldId);
//	$.get('ajax.render.php?class=' + sClass + '&json_obj=' + oJSON.value + '&att_code=' + sAttCode,
//	   { operation: "allowed_values" },
//	   function(data){
//		 //$('#field_'+iFieldId).html(data);
//		}
//	);
//}
//
//function AjaxGetDefaultValue(oObj, sClass, sAttCode, iFieldId)
//{
//	// Asynchronously call the server to provide a default value if the field is
//	// empty
//	if (oObj['m_aCurrValues'][sAttCode] == '')
//	{
//		var oJSON = document.getElementById(sJsonFieldId);
//		$.get('ajax.render.php?class=' + sClass + '&json_obj=' + oJSON.value + '&att_code=' + sAttCode,
//		   { operation: "default_value" },
//		   function(json_data){
//			 var oObj = ReloadObjectFromServer(json_data);
//			 UpdateFieldFromObject(iFieldId, aFieldsMap, oObj)
//			}
//		);
//	}
//}

// Store the result of the form validation... there may be several forms per page, beware
var oFormErrors = { err_form0: 0 };

function CheckFields(sFormId)
{
	$('#'+sFormId+' :submit').attr('disable', 'disabled');
	$('#'+sFormId+' :button[type=submit]').attr('disable', 'disabled');
	firstErrorId = '';

	// The two 'fields' below will be updated when the 'validate' event is processed
	oFormErrors['err_'+sFormId] = 0;		// Number of errors encountered when validating the form
	oFormErrors['input_'+sFormId] = null;	// First 'input' with an error, to set the focus to it
	$('#'+sFormId+' :input').each( function()
	{
		validateEventResult = $(this).trigger('validate', sFormId);
	}
	);
	if(oFormErrors['err_'+sFormId] > 0)
	{
		alert('Please fill-in all mandatory fields before continuing.');
		$('#'+sFormId+' :submit').attr('disable', '');
		$('#'+sFormId+' :button[type=submit]').attr('disable', '');
		if (oFormErrors['input_'+sFormId] != null)
		{
			$('#'+oFormErrors['input_'+sFormId]).focus();
		}
	}
	return (oFormErrors['err_'+sFormId] == 0); // If no error, submit the form
}

function ValidateField(sFieldId, sPattern, bMandatory, sFormId)
{
	var bValid = true;
	var currentVal = $('#'+sFieldId).val();
	if (bMandatory && ((currentVal == '') || (currentVal == 0)))
	{
		bValid = false;
	}
	else if (sPattern != '')
	{
		re = new RegExp(sPattern);
		//console.log('Validating field: '+sFieldId + ' current value: '+currentVal + ' pattern: '+sPattern );
		bValid = re.test(currentVal);
	}
	if (bValid)
	{
		// Visual feedback
		$('#v_'+sFieldId).html('');
	}
	else
	{
		// Report the error...
		oFormErrors['err_'+sFormId]++;
		if (oFormErrors['input_'+sFormId] == null)
		{
			// Let's remember the first input with an error, so that we can put back the focus on it later
			oFormErrors['input_'+sFormId] = sFieldId;
		}
		// Visual feedback
		$('#v_'+sFieldId).html('');
	}
	//console.log('Form: '+sFormId+' Validating field: '+sFieldId + ' current value: '+currentVal+' pattern: '+sPattern+' result: '+bValid );
	return bValid;
}

function UpdateDependentFields(aFieldNames)
{
	//console.log('UpdateDependentFields:');
	//console.log(aFieldNames);
	index = 0;
	oWizardHelper.ResetQuery();
	oWizardHelper.UpdateWizard();
	while(index < aFieldNames.length )
	{
		sAttCode = aFieldNames[index];
		oWizardHelper.RequestAllowedValues(sAttCode);
		index++;
	}
	oWizardHelper.AjaxQueryServer();
}
<commit_msg>- Non mandatory fields can be empty, even if a validation pattern was specified.<commit_after>// ID of the (hidden) form field used to store the JSON representation of the
// object being edited in this page
var sJsonFieldId = 'json_object';

// The memory representation of the object
var oObj = {};

// Mapping between the fields of the form and the attribute of the current object
// If aFieldsMap[2] contains 'foo' it means that oObj.foo corresponds to the field
// of Id 'att_2' in the form
var aFieldsMap = new Array;

// Update the whole object from the form and also update its
// JSON (serialized) representation in the (hidden) field
function UpdateObjectFromForm(aFieldsMap, oObj)
{
	for(i=0; i<aFieldsMap.length; i++)
	{
		var oElement = document.getElementById('att_'+i);
		var sFieldName = aFieldsMap[i];
		oObj['m_aCurrValues'][sFieldName] = oElement.value;
		sJSON = JSON.stringify(oObj);
		var oJSON = document.getElementById(sJsonFieldId);
		oJSON.value = sJSON;
	}
	return oObj;
}

// Update the specified field from the current object
function UpdateFieldFromObject(idField, aFieldsMap, oObj)
{
	var oElement = document.getElementById('att_'+idField);
	oElement.value = oObj['m_aCurrValues'][aFieldsMap[idField]];
}
// Update all the fields of the Form from the current object
function UpdateFormFromObject(aFieldsMap, oObj)
{
	for(i=0; i<aFieldsMap.length; i++)
	{
		UpdateFieldFromForm(i, aFieldsMap, oObj);
	}
}

// This function is meant to be called from the AJAX page
// It reloads the object (oObj) from the JSON representation
// and also updates the form field that contains the JSON
// representation of the object
function ReloadObjectFromServer(sJSON)
{
	//console.log('JSON value:', sJSON);
	var oJSON = document.getElementById(sJsonFieldId);
	oJSON.value = sJSON;
	oObj = JSON.parse( '(' + sJSON + ')' );
	return oObj;
}

function GoToStep(iCurrentStep, iNextStep)
{
	var oCurrentStep = document.getElementById('wizStep'+iCurrentStep);
	if (iNextStep > iCurrentStep)
	{
		// Check the values when moving forward
		if (CheckFields('wizStep'+iCurrentStep))
		{
			oCurrentStep.style.display = 'none';
			ActivateStep(iNextStep);
		}
	}
	else
	{
		oCurrentStep.style.display = 'none';
		ActivateStep(iNextStep);
	}
}

function ActivateStep(iTargetStep)
{
	UpdateObjectFromForm(aFieldsMap, oObj);
	var oNextStep = document.getElementById('wizStep'+(iTargetStep));
	window.location.href='#step'+iTargetStep;
	// If a handler for entering this step exists, call it
	if (typeof(this['OnEnterStep'+iTargetStep]) == 'function')
	{
		eval( 'OnEnterStep'+iTargetStep+'();');
	}
	oNextStep.style.display = '';
	G_iCurrentStep = iTargetStep;
	//$('#wizStep'+(iTargetStep)).block({ message: null });
}

//function AjaxGetValuesDef(oObj, sClass, sAttCode, iFieldId)
//{
//	var oJSON = document.getElementById(sJsonFieldId);
//	$.get('ajax.render.php?class=' + sClass + '&json_obj=' + oJSON.value + '&att_code=' + sAttCode,
//	   { operation: "allowed_values" },
//	   function(data){
//		 //$('#field_'+iFieldId).html(data);
//		}
//	);
//}
//
//function AjaxGetDefaultValue(oObj, sClass, sAttCode, iFieldId)
//{
//	// Asynchronously call the server to provide a default value if the field is
//	// empty
//	if (oObj['m_aCurrValues'][sAttCode] == '')
//	{
//		var oJSON = document.getElementById(sJsonFieldId);
//		$.get('ajax.render.php?class=' + sClass + '&json_obj=' + oJSON.value + '&att_code=' + sAttCode,
//		   { operation: "default_value" },
//		   function(json_data){
//			 var oObj = ReloadObjectFromServer(json_data);
//			 UpdateFieldFromObject(iFieldId, aFieldsMap, oObj)
//			}
//		);
//	}
//}

// Store the result of the form validation... there may be several forms per page, beware
var oFormErrors = { err_form0: 0 };

function CheckFields(sFormId)
{
	$('#'+sFormId+' :submit').attr('disable', 'disabled');
	$('#'+sFormId+' :button[type=submit]').attr('disable', 'disabled');
	firstErrorId = '';

	// The two 'fields' below will be updated when the 'validate' event is processed
	oFormErrors['err_'+sFormId] = 0;		// Number of errors encountered when validating the form
	oFormErrors['input_'+sFormId] = null;	// First 'input' with an error, to set the focus to it
	$('#'+sFormId+' :input').each( function()
	{
		validateEventResult = $(this).trigger('validate', sFormId);
	}
	);
	if(oFormErrors['err_'+sFormId] > 0)
	{
		alert('Please fill-in all mandatory fields before continuing.');
		$('#'+sFormId+' :submit').attr('disable', '');
		$('#'+sFormId+' :button[type=submit]').attr('disable', '');
		if (oFormErrors['input_'+sFormId] != null)
		{
			$('#'+oFormErrors['input_'+sFormId]).focus();
		}
	}
	return (oFormErrors['err_'+sFormId] == 0); // If no error, submit the form
}

function ValidateField(sFieldId, sPattern, bMandatory, sFormId)
{
	var bValid = true;
	var currentVal = $('#'+sFieldId).val();
	if (bMandatory && ((currentVal == '') || (currentVal == 0)))
	{
		bValid = false;
	}
	else if ((currentVal == '') || (currentVal == 0))
	{
		// An empty field is Ok...
		bValid = true;
	}
	else if (sPattern != '')
	{
		re = new RegExp(sPattern);
		//console.log('Validating field: '+sFieldId + ' current value: '+currentVal + ' pattern: '+sPattern );
		bValid = re.test(currentVal);
	}
	if (bValid)
	{
		// Visual feedback
		$('#v_'+sFieldId).html('');
	}
	else
	{
		// Report the error...
		oFormErrors['err_'+sFormId]++;
		if (oFormErrors['input_'+sFormId] == null)
		{
			// Let's remember the first input with an error, so that we can put back the focus on it later
			oFormErrors['input_'+sFormId] = sFieldId;
		}
		// Visual feedback
		$('#v_'+sFieldId).html('');
	}
	//console.log('Form: '+sFormId+' Validating field: '+sFieldId + ' current value: '+currentVal+' pattern: '+sPattern+' result: '+bValid );
	return bValid;
}

function UpdateDependentFields(aFieldNames)
{
	//console.log('UpdateDependentFields:');
	//console.log(aFieldNames);
	index = 0;
	oWizardHelper.ResetQuery();
	oWizardHelper.UpdateWizard();
	while(index < aFieldNames.length )
	{
		sAttCode = aFieldNames[index];
		oWizardHelper.RequestAllowedValues(sAttCode);
		index++;
	}
	oWizardHelper.AjaxQueryServer();
}
<|endoftext|>


<commit_before>"use strict";

/*
 *  lisTours bundle entry point (index.js).
 */
var lisTours = {}; /* the lisTours library, created by this module */

(function(){
  var that = this;
  var TOUR_ID_KEY = 'lisTourId';
  var MS = 100;
  //adf: doubled this from previous value to accomodate slow gene searches;
  //maybe there's a better approach.
  var MAX_MS = 20000;
  var dependenciesLoaded = false;
  var $ = null;

  if(! window.console )
  {
    // support console.log on old IE versions, if it doesn't exist
    require.ensure(['console-shim'], function(require) {
      require('console-shim');
    });
  }

  /* loadDeps() : use webpack lazy loading to load the dependencies of
   * lisTours only if a tour is requested or tour in progress.
   */
  this.loadDeps = function(cb) {
    require.ensure(['jquery',
		    '!style!css!../css/bootstrap-tour-standalone.min.css',
		    '!style!css!../css/lis-tours.css',
		    './bootstrap-tour-loader.js',
		    './tours/index.js'],
       function(require) {
	 // JQuery: load our version of jquery and stash it in a global
	 // var, taking care not to conflict with existing, older, jquery,
	 // e.g. drupal7 requires jquery 1.4.4 (Bootstrap Tours requires
	 // jquery Deferred/Promise classes)
	 $ = window.__jquery = require('jquery').noConflict(true);
	 // load the bootstrap tours css
	 require('!style!css!../css/bootstrap-tour-standalone.min.css');
	 require('!style!css!../css/lis-tours.css');
	 // load a customized bootstrap tour js (consumes our __jquery version)
	 require('./bootstrap-tour-loader.js');
	 // load tour definitions
	 require('./tours/index.js');
	 // callback fn
	 cb.call(that);
       });
  };

  /* go() : force a tour to start at step 0.
   */
  this.go = function(tourId) {
    that.loadDeps(function() {
      var tour = that.tours[tourId];
      if(! tour) {
	localStorage.removeItem(TOUR_ID_KEY);
	throw 'failed to load tour id: ' + tourId;
      }
      tour.init();
      tour.end();
      tour.restart();
      localStorage[TOUR_ID_KEY] = tourId;
    });
  };

  /* resume() : restore a tour at whatever step bootstrap tour has
   * retained state.
   */
  this.resume = function(tourId) {
    that.loadDeps(function() {
      var tour = that.tours[tourId];
      if(! tour) {
	localStorage.removeItem(TOUR_ID_KEY);
	throw 'failed to load tour id: ' + tourId;
      }
      tour.init();
      if(tour.ended()) {
	//console.log('removing tour id: ' + tourId) ;
	localStorage.removeItem(TOUR_ID_KEY);
      }
      else {
	var force = true;
	tour.start(force);
      }
    })
  };

  this.tours = {};

  /* register() : each tour object must register, so we can lookup the
   * tour object by it's tag name.
   */
  this.register = function(tour) {
    var name = tour._options.name;
    that.tours[name] = tour;
  };

  this.waitForContent = function(tour, cb) {
    var promise = new $.Deferred();
    var elapsed = 0;
    function waiter() {
      var res = cb();
      if(res) {
	promise.resolve();
	return;
      }
      else {
	elapsed += MS;
	if(elapsed >= MAX_MS) {
	  tour.end();
	  throw 'error: dynamic content timeout ' + elapsed + ' ms : ' + cb;
	}
	//console.log('waiting for dynamic content from callback ' + cb);
	setTimeout(waiter, MS);
      }
    }
    setTimeout(waiter, MS);
    return promise;
  };

  /* init() : lookup the most recent tour id, and load it's module, to
   * enable tour to resume automatically.
   */
  this.init = function() {
    var tourId = localStorage.getItem(TOUR_ID_KEY);
    if(tourId) {
      that.resume(tourId);
    }
  };

  if('jQuery' in window) {
    jQuery('document').ready(that.init);
  }
  else {
    // lazy load our jquery, if there is not one already.
    require.ensure(['jquery'], function(require) {
      window.__jquery = require('jquery').noConflict(true);
      window.__jquery('document').ready(that.init);
    });
  }

}.call(lisTours));

// make the lisTours library available globally
module.exports = lisTours;
window.lisTours = lisTours;
//console.log('lisTours loaded');

<commit_msg>Use jquery(document) instead of jquery('document').<commit_after>"use strict";

/*
 *  lisTours bundle entry point (index.js).
 */
var lisTours = {}; /* the lisTours library, created by this module */

(function(){
  var that = this;
  var TOUR_ID_KEY = 'lisTourId';
  var MS = 100;
  //adf: doubled this from previous value to accomodate slow gene searches;
  //maybe there's a better approach.
  var MAX_MS = 20000;
  var dependenciesLoaded = false;
  var $ = null;

  if(! window.console )
  {
    // support console.log on old IE versions, if it doesn't exist
    require.ensure(['console-shim'], function(require) {
      require('console-shim');
    });
  }

  /* loadDeps() : use webpack lazy loading to load the dependencies of
   * lisTours only if a tour is requested or tour in progress.
   */
  this.loadDeps = function(cb) {
    require.ensure(['jquery',
		    '!style!css!../css/bootstrap-tour-standalone.min.css',
		    '!style!css!../css/lis-tours.css',
		    './bootstrap-tour-loader.js',
		    './tours/index.js'],
       function(require) {
	 // JQuery: load our version of jquery and stash it in a global
	 // var, taking care not to conflict with existing, older, jquery,
	 // e.g. drupal7 requires jquery 1.4.4 (Bootstrap Tours requires
	 // jquery Deferred/Promise classes)
	 $ = window.__jquery = require('jquery').noConflict(true);
	 // load the bootstrap tours css
	 require('!style!css!../css/bootstrap-tour-standalone.min.css');
	 require('!style!css!../css/lis-tours.css');
	 // load a customized bootstrap tour js (consumes our __jquery version)
	 require('./bootstrap-tour-loader.js');
	 // load tour definitions
	 require('./tours/index.js');
	 // callback fn
	 cb.call(that);
       });
  };

  /* go() : force a tour to start at step 0.
   */
  this.go = function(tourId) {
    that.loadDeps(function() {
      var tour = that.tours[tourId];
      if(! tour) {
	localStorage.removeItem(TOUR_ID_KEY);
	throw 'failed to load tour id: ' + tourId;
      }
      tour.init();
      tour.end();
      tour.restart();
      localStorage[TOUR_ID_KEY] = tourId;
    });
  };

  /* resume() : restore a tour at whatever step bootstrap tour has
   * retained state.
   */
  this.resume = function(tourId) {
    that.loadDeps(function() {
      var tour = that.tours[tourId];
      if(! tour) {
	localStorage.removeItem(TOUR_ID_KEY);
	throw 'failed to load tour id: ' + tourId;
      }
      tour.init();
      if(tour.ended()) {
	//console.log('removing tour id: ' + tourId) ;
	localStorage.removeItem(TOUR_ID_KEY);
      }
      else {
	var force = true;
	tour.start(force);
      }
    })
  };

  this.tours = {};

  /* register() : each tour object must register, so we can lookup the
   * tour object by it's tag name.
   */
  this.register = function(tour) {
    var name = tour._options.name;
    that.tours[name] = tour;
  };

  this.waitForContent = function(tour, cb) {
    var promise = new $.Deferred();
    var elapsed = 0;
    function waiter() {
      var res = cb();
      if(res) {
	promise.resolve();
	return;
      }
      else {
	elapsed += MS;
	if(elapsed >= MAX_MS) {
	  tour.end();
	  throw 'error: dynamic content timeout ' + elapsed + ' ms : ' + cb;
	}
	//console.log('waiting for dynamic content from callback ' + cb);
	setTimeout(waiter, MS);
      }
    }
    setTimeout(waiter, MS);
    return promise;
  };

  /* init() : lookup the most recent tour id, and load it's module, to
   * enable tour to resume automatically.
   */
  this.init = function() {
    var tourId = localStorage.getItem(TOUR_ID_KEY);
    if(tourId) {
      that.resume(tourId);
    }
  };

  if('jQuery' in window) {
    jQuery(document).ready(that.init);
  }
  else {
    // lazy load our jquery, if there is not one already.
    require.ensure(['jquery'], function(require) {
      window.__jquery = require('jquery').noConflict(true);
      window.__jquery(document).ready(that.init);
    });
  }

}.call(lisTours));

// make the lisTours library available globally
module.exports = lisTours;
window.lisTours = lisTours;
//console.log('lisTours loaded');
<|endoftext|>