<commit_before>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        // JavaScript to be fired on all pages
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    },
    // About us page, note the change from about-us to about_us.
    'about_us': {
      init: function() {
        // JavaScript to be fired on the about us page
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

})(jQuery); // Fully reference jQuery after this point.

  $(document).foundation();

  var $grid = $('.lookbookgrid').isotope({
    itemSelector: '.grid-item',
    percentPosition: true,
    masonry: {
      columnWidth: '.grid-sizer',
      gutter: 0
    }
  });

  $grid.imagesLoaded().progress( function() {
    $grid.isotope('layout');
  });

$('document').ready(function(){

  /*** Required data param for inputs ***/
  $('.woocommerce-billing-fields .validate-required').find('input[type=text], input[type=email]').prop('required','true');

  $('#createaccount').on('change',function(e) {
    if ($(this).prop('checked')) {
      $('.create-account .validate-required').find('input').prop('required','true');
    } else {
      $('.create-account .validate-required').find('input').prop('required','false');
    }
  });

  $('#ship-to-different-address-checkbox').on('change',function(e) {
    if ($(this).prop('checked')) {
      $('.woocommerce-shipping-fields .validate-required').find('input').prop('required','true');
    } else {
      $('.woocommerce-shipping-fields .validate-required').find('input').prop('required','false');
    }
  });

  /*** Thumbnail Carousel on Single product Page ***/
  var prodthumbsOwl = $('.prodthumbs');

  prodthumbsOwl.owlCarousel({
    pagination:false,
    navigation : false,

    items : 4, //10 items above 1000px browser width
    itemsDesktop : [1024,3], //5 items between 1000px and 901px
    itemsDesktopSmall : [768,3], // betweem 900px and 601px
    itemsTablet: [480,3], //2 items between 480 and 0
    itemsMobile : false // itemsMobile disabled - inherit from itemsTablet option
  });

  var prodOwl = $('.prod-carousel');

  prodOwl.owlCarousel({
    pagination:false,
    navigation : false,

    items : 6, //10 items above 1000px browser width
    itemsDesktop : [1280,5], //5 items between 1000px and 901px
    itemsDesktopSmall : [1024,4], // betweem 900px and 601px
    itemsTablet: [768,3], //2 items between 480 and 0
    itemsMobile : [480,2] // itemsMobile disabled - inherit from itemsTablet option
  });

  $('.lookbookgrid').magnificPopup({
    delegate: 'a',
    type: 'image',
    tLoading: 'Loading image #%curr%...',
    mainClass: 'mfp-img-mobile',
    gallery: {
      enabled: true,
      navigateByImgClick: true,
      preload: [0,1] // Will preload 0 - before current, and 1 after the current image
    },
    image: {
      tError: 'The image #%curr% could not be loaded.',
      titleSrc: function(item) {
        return /*item.el.children().attr('alt') + */'&copy DogDays Yoga Wear';
      }
    }
  });

  $('.woocommerce-main-image').magnificPopup({
    type: 'image',
    closeOnContentClick: true,
    closeBtnInside: false,
    fixedContentPos: true,
    mainClass: 'mfp-no-margins mfp-with-zoom', // class to remove default margin from left and right side
    image: {
      verticalFit: true
    },
    zoom: {
      enabled: true,
      duration: 300 // don't foget to change the duration also in CSS
    }
  });

  $('.popup-youtube, .popup-vimeo, .popup-gmaps').magnificPopup({
    disableOn: 700,
    type: 'iframe',
    mainClass: 'mfp-fade',
    removalDelay: 160,
    preloader: false,

    fixedContentPos: false
  });

  $('.woocommerce-main-image').zoom({
      url: $('.woocommerce-main-image').attr('href'),
      magnify: 0.75,
   });

  $('.prodthumbs .item a').on('click', function(e) {
   e.preventDefault();
   $('.woocommerce-main-image').trigger('zoom.destroy');
   $('.woocommerce-main-image').css('min-height', $('.woocommerce-main-image .attachment-shop_single').height());
   $('.woocommerce-main-image').attr('href', $(this).attr('href') );
   $('.woocommerce-main-image .attachment-shop_single').replaceWith($(this).data('swapimage'));
   $('.woocommerce-main-image').zoom({
      url: $('.woocommerce-main-image').attr('href'),
      magnify: 0.75
   });

   setTimeout(function() { $('.woocommerce-main-image').css('min-height', 'auto'); } , 2000)
  });

});
<commit_msg>miss semicolon<commit_after>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        // JavaScript to be fired on all pages
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    },
    // About us page, note the change from about-us to about_us.
    'about_us': {
      init: function() {
        // JavaScript to be fired on the about us page
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

})(jQuery); // Fully reference jQuery after this point.

  $(document).foundation();

  var $grid = $('.lookbookgrid').isotope({
    itemSelector: '.grid-item',
    percentPosition: true,
    masonry: {
      columnWidth: '.grid-sizer',
      gutter: 0
    }
  });

  $grid.imagesLoaded().progress( function() {
    $grid.isotope('layout');
  });

$('document').ready(function(){

  /*** Required data param for inputs ***/
  $('.woocommerce-billing-fields .validate-required').find('input[type=text], input[type=email]').prop('required','true');

  $('#createaccount').on('change',function(e) {
    if ($(this).prop('checked')) {
      $('.create-account .validate-required').find('input').prop('required','true');
    } else {
      $('.create-account .validate-required').find('input').prop('required','false');
    }
  });

  $('#ship-to-different-address-checkbox').on('change',function(e) {
    if ($(this).prop('checked')) {
      $('.woocommerce-shipping-fields .validate-required').find('input').prop('required','true');
    } else {
      $('.woocommerce-shipping-fields .validate-required').find('input').prop('required','false');
    }
  });

  /*** Thumbnail Carousel on Single product Page ***/
  var prodthumbsOwl = $('.prodthumbs');

  prodthumbsOwl.owlCarousel({
    pagination:false,
    navigation : false,

    items : 4, //10 items above 1000px browser width
    itemsDesktop : [1024,3], //5 items between 1000px and 901px
    itemsDesktopSmall : [768,3], // betweem 900px and 601px
    itemsTablet: [480,3], //2 items between 480 and 0
    itemsMobile : false // itemsMobile disabled - inherit from itemsTablet option
  });

  var prodOwl = $('.prod-carousel');

  prodOwl.owlCarousel({
    pagination:false,
    navigation : false,

    items : 6, //10 items above 1000px browser width
    itemsDesktop : [1280,5], //5 items between 1000px and 901px
    itemsDesktopSmall : [1024,4], // betweem 900px and 601px
    itemsTablet: [768,3], //2 items between 480 and 0
    itemsMobile : [480,2] // itemsMobile disabled - inherit from itemsTablet option
  });

  $('.lookbookgrid').magnificPopup({
    delegate: 'a',
    type: 'image',
    tLoading: 'Loading image #%curr%...',
    mainClass: 'mfp-img-mobile',
    gallery: {
      enabled: true,
      navigateByImgClick: true,
      preload: [0,1] // Will preload 0 - before current, and 1 after the current image
    },
    image: {
      tError: 'The image #%curr% could not be loaded.',
      titleSrc: function(item) {
        return /*item.el.children().attr('alt') + */'&copy DogDays Yoga Wear';
      }
    }
  });

  $('.woocommerce-main-image').magnificPopup({
    type: 'image',
    closeOnContentClick: true,
    closeBtnInside: false,
    fixedContentPos: true,
    mainClass: 'mfp-no-margins mfp-with-zoom', // class to remove default margin from left and right side
    image: {
      verticalFit: true
    },
    zoom: {
      enabled: true,
      duration: 300 // don't foget to change the duration also in CSS
    }
  });

  $('.popup-youtube, .popup-vimeo, .popup-gmaps').magnificPopup({
    disableOn: 700,
    type: 'iframe',
    mainClass: 'mfp-fade',
    removalDelay: 160,
    preloader: false,

    fixedContentPos: false
  });

  $('.woocommerce-main-image').zoom({
      url: $('.woocommerce-main-image').attr('href'),
      magnify: 0.75,
   });

  $('.prodthumbs .item a').on('click', function(e) {
   e.preventDefault();
   $('.woocommerce-main-image').trigger('zoom.destroy');
   $('.woocommerce-main-image').css('min-height', $('.woocommerce-main-image .attachment-shop_single').height());
   $('.woocommerce-main-image').attr('href', $(this).attr('href') );
   $('.woocommerce-main-image .attachment-shop_single').replaceWith($(this).data('swapimage'));
   $('.woocommerce-main-image').zoom({
      url: $('.woocommerce-main-image').attr('href'),
      magnify: 0.75
   });

   setTimeout(function() { $('.woocommerce-main-image').css('min-height', 'auto'); } , 2000);
  });

});
<|endoftext|>


<commit_before>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Create parallax effect in jumbo
  function parallaxIt() {
    $(window).on("resize scroll",function(){
      var scrollTop = window.pageYOffset;
      var $jumbo = $('.jumbo');
      var height = $jumbo.height();
      if (scrollTop > 0 && scrollTop < height) {
        var imageScrolledPercent = scrollTop / height * 100;
        var coords = '50% calc(50% + ' + imageScrolledPercent.toFixed(2) + 'px)';
        requestAnimationFrame(function() {
          $jumbo.css({ backgroundPosition: coords })
        });
      }
    });
  }

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        // JavaScript to be fired on all pages
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
        requestAnimationFrame(function() {
          parallaxIt()
        });
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    },
    // About us page, note the change from about-us to about_us.
    'about_us': {
      init: function() {
        // JavaScript to be fired on the about us page
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

})(jQuery); // Fully reference jQuery after this point.
<commit_msg>Scroll top fix<commit_after>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Create parallax effect in jumbo
  function parallaxIt() {
    $(window).on("resize scroll",function(){
      var scrollTop = window.pageYOffset;
      var $jumbo = $('.jumbo');
      var height = $jumbo.height();
      if (scrollTop > 0 && scrollTop < height) {
        var coords = '50% calc(50% + ' + scrollTop.toFixed(2) / 3 + 'px)';
        requestAnimationFrame(function() {
          $jumbo.css({ backgroundPosition: coords })
        });
      }
    });
  }

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        // JavaScript to be fired on all pages
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
        requestAnimationFrame(function() {
          parallaxIt()
        });
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    },
    // About us page, note the change from about-us to about_us.
    'about_us': {
      init: function() {
        // JavaScript to be fired on the about us page
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

})(jQuery); // Fully reference jQuery after this point.
<|endoftext|>


<commit_before>// This is the module for starring and unstarring modules in the browser.
// It uses a localStorage cache to maintain a list of recent starrings
// and unstarrings, while the remote registry cache catches up.

var $ = require("jquery");

var star = module.exports = function() {
  $(star.init);
  return star;
}

star.init = function() {
  star.form = $('form.star')
  if (!star.form) return
  star.form.checkbox = star.form.find('input[type=checkbox]')

  star.form.checkbox.on('change', star.onChange)

  // Check the checkbox if we arrived from the login page and there's a #star
  // fragment in the URL
  if (String(document.referrer).match("/login") && String(location.hash).match("#star")) {
    console.log("post-login starring...")
    star.form.checkbox.prop("checked", true);
  }
}

star.onChange = function() {
  var data = {}

  // Gather data from the form inputs
  // jQuery gotcha: If checkbox is unchecked, it won't be included in this array.
  star.form.serializeArray().forEach(function(input){
    data[input.name] = input.value;
  })

  // JavaScript is loosely typed...
  data.isStarred = Boolean(data.isStarred)

  // Update count in label
  var count = Number(star.form.find("label").text())
  data.isStarred ? ++count : --count
  star.form.find("label").text(count)

  $.ajax({
    url: '/star',
    data: data,
    type: 'POST',
    headers: {'x-csrf-token': data.crumb}
  })
    .done(star.onDone)
    .error(star.onError)
}

star.onDone = function (resp) {
  // console.log(resp)
}

star.onError = function (xhr, status, error) {
  if (xhr && xhr.status && Number(xhr.status) === 403) {
    window.location = "/login?done="+location.pathname+"#star"
    return
  } else {
    console.error(xhr)
  }
}
<commit_msg>tidy up the comments in the star module<commit_after>// This is the module for starring and unstarring modules in the browser.

var $ = require("jquery");

var star = module.exports = function() {
  $(star.init);
  return star;
}

star.init = function() {
  star.form = $('form.star')
  if (!star.form) return
  star.form.checkbox = star.form.find('input[type=checkbox]')

  star.form.checkbox.on('change', star.onChange)

  // Check the checkbox if we arrived from the login page
  // and there's a #star fragment in the URL
  if (String(document.referrer).match("/login") && String(location.hash).match("#star")) {
    console.log("post-login starring...")
    star.form.checkbox.prop("checked", true);
  }
}

star.onChange = function() {
  var data = {}

  // Gather data from the form inputs
  // jQuery gotcha: If checkbox is unchecked, it won't be included in this array.
  star.form.serializeArray().forEach(function(input){
    data[input.name] = input.value;
  })

  // JavaScript is loosely typed...
  data.isStarred = Boolean(data.isStarred)

  // Update count in label
  var count = Number(star.form.find("label").text())
  data.isStarred ? ++count : --count
  star.form.find("label").text(count)

  $.ajax({
    url: '/star',
    data: data,
    type: 'POST',
    headers: {'x-csrf-token': data.crumb}
  })
    .done(star.onDone)
    .error(star.onError)
}

star.onDone = function (data) {
  // console.log(data)
}

star.onError = function (xhr, status, error) {
  // Redirect to login page if we got a 403
  if (xhr && xhr.status && Number(xhr.status) === 403) {
    window.location = "/login?done="+location.pathname+"#star"
    return
  }

  console.error(xhr)
}
<|endoftext|>


<commit_before>/***********
Spaz_Tooltip
***********/

var Spaz_Tooltip_Timeout = {};
var Spaz_Tooltip_hideTimeout = {};

function Spaz_Tooltip(opts) {
	this.event		= opts.e;
	this.el			= opts.el;
	this.str		= opts.str;
	this.previewurl = opts.previewurl;
}

Spaz_Tooltip.prototype.show = function() {

	/*
		Hide any open tooltips
	*/
	$('#tooltip').stop().hide().css('width', '').css('height', '');

	/*
		clear any running tooltip timeouts
	*/
	clearTimeout(Spaz_Tooltip_Timeout);
	clearTimeout(Spaz_Tooltip_hideTimeout);

	/*
		We have to make a closure here to solve the scoping problems
		with accessing object properties in the setTimeout callback
	*/
	var thisTT = this;

	//air.trace('delaying tooltip "'+this.str+'" for 500 mseconds');

	Spaz_Tooltip_Timeout = setTimeout(delayedShow, Spaz.Prefs.get('window-tooltipdelay'));

	function delayedShow() {
		Spaz.dump('showing tooltip "'+thisTT.str+'"');

		if (!thisTT.event) {
			Spaz.dump('No event found in Spaz_Tooltip.show; returning');
			return;
		}

		// Spaz.dump(thisTT.el);

		// air.trace("message: "+thisTT.str);

		// var minwidth = 100;

		// air.trace('EVENT')
		// Spaz.dump(thisTT.event)
		// air.trace('EL')
		// Spaz.dump(thisTT.el)
		// air.trace('STR')
		// Spaz.dump(thisTT.str)
		// air.trace('PREVIEWURL')
		// Spaz.dump(thisTT.previewurl)
		// air.trace('ARGUMENTS')
		// Spaz.dump(arguments)

		// show the tooltip
		$('#tooltip').css('left', thisTT.event.pageX+10)
			.css('top',  thisTT.event.pageY+20)
			.show()
			.css('opacity', 0)
			.animate({'opacity':'0.85'}, {speed:'fast'});
			// .animate({'opacity':'0.85'}, {speed:200, queue:false});

		$('#tooltip').children('.tooltip-msg').html(thisTT.str);
		$('#tooltip').children('.preview').empty();

		// Spaz.dump(tt[0].outerHTML);

		// Reset the .preview div ID so we don't display the wrong preview
		$('#tooltip').children('.preview').attr('id', '')

		if ($(thisTT.el).attr('user-screen_name')) {

			Spaz.dump('This is a user profile tooltip')

			//var username = $(thisTT.el).text().replace(/@/, '');
			var username = $(thisTT.el).attr('user-screen_name');

			Spaz.dump('username is '+username)

			var url = Spaz.Data.getAPIURL('user_timeline')
			var data = {
				'id':username,
				'count':1
			}

			var previewid = "preview-username-"+username;

			Spaz.dump('previewid = '+previewid);

			$('#tooltip').children('.preview').attr('id', previewid)

			$.get(url, data, function(data, textStatus) {
				// air.trace('textStatus:'+textStatus);
				// air.trace('DATA:'+data);
				try {
					var tweets = JSON.parse(data);

					Spaz.dump(tweets);

					if (tweets.error) {
						Spaz.dump('Error when getting preview data for tooltip');
						$('#tooltip').children('.preview').empty();
						$('#tooltip').children('.preview').append("
Could not retrieve user. Probably protected.
");
						$('#tooltip').children('.preview').append("
Error message from Twitter:\""+tweets.error+"\"
");
						Spaz.dump($('#tooltip')[0].outerHTML);
					} else {

						// air.trace('No errors when getting preview data for tooltip');
						if (tweets[0].text) {

							$('#'+previewid).empty();
							$('#'+previewid).append("");
							$('#'+previewid).append("
"+tweets[0].user.name+" ("+tweets[0].user.screen_name+")
");
							if (tweets[0].user.location) {
								$('#'+previewid).append("
"+tweets[0].user.location+"
");
							}
							if (tweets[0].user.followers_count) {
								$('#'+previewid).append("
"+tweets[0].user.followers_count+" followers
");
							}
							if (tweets[0].user.description) {
								$('#'+previewid).append("
"+tweets[0].user.description+"
");
							}
							$('#'+previewid).append('
Latest: '+tweets[0].text+'
');
							Spaz.dump($('#tooltip')[0].outerHTML);
						}

						$('#'+previewid).fadeIn(500);
						thisTT.resetTooltipPosition();

					}
					Spaz.dump($('#tooltip')[0].outerHTML);
				} catch(e) {
					Spaz.dump("An exception occurred when eval'ing the returned data. Error name: " + e.name
					+ ". Error message: " + e.message)
				}
			})

		} else if (thisTT.previewurl) {

			Spaz.dump('This is an URL preview tooltip')

			var previewid = "preview-link-"+getTimeAsInt();

			Spaz.dump('previewid = '+previewid);

			$('#tooltip').children('.preview').attr('id', previewid)

			if (thisTT.previewurl.search(/^http:\/\//i) > -1) {

				$.get(thisTT.previewurl, function(rtext, status, xhr) {
					// air.trace('rtext:'+rtext);
					var rtext_matches = rtext.match(/<title>([^<]*)<\/title>/mi);

					// alert(rtext_matches);

					if (rtext_matches && rtext_matches[1]) {
						var title = rtext_matches[1];
						// air.trace('jqpreview.innerText:'+jqpreview[0].innerText);
						$('#tooltip').children('.preview').empty();
						$('#'+previewid).html('Title: '+title);
						$('#'+previewid).fadeIn(500);
						thisTT.resetPosition()
					}
				});
			}

		}

		var vp  = Spaz.UI.getViewport();
		var off = $('#tooltip').offset();

		// air.trace('Viewport:')
		// Spaz.dump(vp);
		// air.trace('Offset:')
		// Spaz.dump(off);

		// check horizontal position
		if (vp.x + vp.cx < off.left + $('#tooltip').width()) {
			// air.trace('horz over')
			$('#tooltip').css('left', parseInt($('#tooltip').css('left')) - ($('#tooltip').width() + 20));
			if ($('#tooltip').offset().left < 5) {
				$('#tooltip').css('left', 5);
			}
		}

		// check vertical position
		if(vp.y + vp.cy < off.top + $('#tooltip').height()) {
			// air.trace('vert over');
			$('#tooltip').css('top', parseInt($('#tooltip').css('top')) - ($('#tooltip').height() + 20));
			if ($('#tooltip').offset().top < 5) {
				$('#tooltip').css('top', 5);
			}
		}

		// air.trace('setting tooltip hide timeout');

		// air.trace('Tooltip hide delay:'+Spaz.Prefs.get('window-tooltiphidedelay'));

		Spaz_Tooltip_hideTimeout = setTimeout(Spaz.UI.hideTooltips, Spaz.Prefs.get('window-tooltiphidedelay'));
		// $('#tooltip').bind('mouseout', Spaz.UI.hideTooltips);
	}

}

/*
	I kinda stole this from the excellent jquery.tooltip
*/
Spaz_Tooltip.prototype.resetPosition = function() {
	var vp  = Spaz.UI.getViewport();
	var off = $('#tooltip').offset();

	// Spaz.dump(vp);
	// Spaz.dump(off);

	// Spaz.dump('reset width');
	// Spaz.dump("old width: "+$('#tooltip').width());

	var newWidth = vp.cx - off.left - 10;
	$('#tooltip').width( newWidth );

	// Spaz.dump("old width: "+newWidth);
};

<commit_msg>add support for twitpic thumbnail preview in the tooltip<commit_after>/***********
Spaz_Tooltip
***********/

var Spaz_Tooltip_Timeout = {};
var Spaz_Tooltip_hideTimeout = {};

function Spaz_Tooltip(opts) {
	this.event		= opts.e;
	this.el			= opts.el;
	this.str		= opts.str;
	this.previewurl = opts.previewurl;
}

Spaz_Tooltip.prototype.show = function() {

	/*
		Hide any open tooltips
	*/
	$('#tooltip').stop().hide().css('width', '').css('height', '');

	/*
		clear any running tooltip timeouts
	*/
	clearTimeout(Spaz_Tooltip_Timeout);
	clearTimeout(Spaz_Tooltip_hideTimeout);

	/*
		We have to make a closure here to solve the scoping problems
		with accessing object properties in the setTimeout callback
	*/
	var thisTT = this;

	//air.trace('delaying tooltip "'+this.str+'" for 500 mseconds');

	Spaz_Tooltip_Timeout = setTimeout(delayedShow, Spaz.Prefs.get('window-tooltipdelay'));

	function delayedShow() {
		Spaz.dump('showing tooltip "'+thisTT.str+'"');

		if (!thisTT.event) {
			Spaz.dump('No event found in Spaz_Tooltip.show; returning');
			return;
		}

		// Spaz.dump(thisTT.el);

		// air.trace("message: "+thisTT.str);

		// var minwidth = 100;

		// air.trace('EVENT')
		// Spaz.dump(thisTT.event)
		// air.trace('EL')
		// Spaz.dump(thisTT.el)
		// air.trace('STR')
		// Spaz.dump(thisTT.str)
		// air.trace('PREVIEWURL')
		// Spaz.dump(thisTT.previewurl)
		// air.trace('ARGUMENTS')
		// Spaz.dump(arguments)

		// show the tooltip
		$('#tooltip').css('left', thisTT.event.pageX+10)
			.css('top',  thisTT.event.pageY+20)
			.show()
			.css('opacity', 0)
			.animate({'opacity':'0.85'}, {speed:'fast'});
			// .animate({'opacity':'0.85'}, {speed:200, queue:false});

		$('#tooltip').children('.tooltip-msg').html(thisTT.str);
		$('#tooltip').children('.preview').empty();

		// Spaz.dump(tt[0].outerHTML);

		// Reset the .preview div ID so we don't display the wrong preview
		$('#tooltip').children('.preview').attr('id', '')

		if ($(thisTT.el).attr('user-screen_name')) {

			Spaz.dump('This is a user profile tooltip')

			//var username = $(thisTT.el).text().replace(/@/, '');
			var username = $(thisTT.el).attr('user-screen_name');

			Spaz.dump('username is '+username)

			var url = Spaz.Data.getAPIURL('user_timeline')
			var data = {
				'id':username,
				'count':1
			}

			var previewid = "preview-username-"+username;

			Spaz.dump('previewid = '+previewid);

			$('#tooltip').children('.preview').attr('id', previewid)

			$.get(url, data, function(data, textStatus) {
				// air.trace('textStatus:'+textStatus);
				// air.trace('DATA:'+data);
				try {
					var tweets = JSON.parse(data);

					Spaz.dump(tweets);

					if (tweets.error) {
						Spaz.dump('Error when getting preview data for tooltip');
						$('#tooltip').children('.preview').empty();
						$('#tooltip').children('.preview').append("
Could not retrieve user. Probably protected.
");
						$('#tooltip').children('.preview').append("
Error message from Twitter:\""+tweets.error+"\"
");
						Spaz.dump($('#tooltip')[0].outerHTML);
					} else {

						// air.trace('No errors when getting preview data for tooltip');
						if (tweets[0].text) {

							$('#'+previewid).empty();
							$('#'+previewid).append("");
							$('#'+previewid).append("
"+tweets[0].user.name+" ("+tweets[0].user.screen_name+")
");
							if (tweets[0].user.location) {
								$('#'+previewid).append("
"+tweets[0].user.location+"
");
							}
							if (tweets[0].user.followers_count) {
								$('#'+previewid).append("
"+tweets[0].user.followers_count+" followers
");
							}
							if (tweets[0].user.description) {
								$('#'+previewid).append("
"+tweets[0].user.description+"
");
							}
							$('#'+previewid).append('
Latest: '+tweets[0].text+'
');
							Spaz.dump($('#tooltip')[0].outerHTML);
						}

						$('#'+previewid).fadeIn(500);
						thisTT.resetTooltipPosition();

					}
					Spaz.dump($('#tooltip')[0].outerHTML);
				} catch(e) {
					Spaz.dump("An exception occurred when eval'ing the returned data. Error name: " + e.name
					+ ". Error message: " + e.message)
				}
			})

		} else if (thisTT.previewurl) {

			Spaz.dump('This is an URL preview tooltip')

			var previewid = "preview-link-"+getTimeAsInt();

			Spaz.dump('previewid = '+previewid);

			$('#tooltip').children('.preview').attr('id', previewid)

         if (thisTT.previewurl.search(/^http:\/\//i) > -1) {

            // Support for twitpic
            var done = false;

            //
            var twitpicRE = new RegExp("^(http:\\/\\/" + "twitpic.com\\/)" + "(.*)$");
            var twitpicMatch = thisTT.previewurl.match(twitpicRE);

            // First detect if we deal with a twitpic URL
            if (twitpicMatch != null)
            {
               var width = $('#tooltip').css("width");
               var widthRE = new RegExp("^([0-9]+)px$");
               var widthMatch = width.match(widthRE);

               // Check the width of the tooltip window is like number + px because we need
               // the value to correctly resize the image
               if (widthMatch != null)
               {
                  width = widthMatch[1];
                  var imgURL = twitpicMatch[1] + "show/thumb/" + twitpicMatch[2] + ".jpg";
                  var s = '';
                  $('#tooltip').children('.preview').empty();
                  $('#'+previewid).html(s);
                  $('#'+previewid).fadeIn(500);
                  thisTT.resetPosition()
                  done = true;
               }
               else
               {
                  air.trace("Could not find the width of the tooltip window " + width);
               }
            }

            if (!done)
            {
               $.get(thisTT.previewurl, function(rtext, status, xhr) {
                  // air.trace('rtext:'+rtext);
                  var rtext_matches = rtext.match(/<title>([^<]*)<\/title>/mi);

                  // alert(rtext_matches);

                  if (rtext_matches && rtext_matches[1]) {
                     var title = rtext_matches[1];
                     // air.trace('jqpreview.innerText:'+jqpreview[0].innerText);
                     $('#tooltip').children('.preview').empty();
                     $('#'+previewid).html('Title: '+title);
                     $('#'+previewid).fadeIn(500);
                     thisTT.resetPosition()
                  }
               });
            }
			}

		}

		var vp  = Spaz.UI.getViewport();
		var off = $('#tooltip').offset();

		// air.trace('Viewport:')
		// Spaz.dump(vp);
		// air.trace('Offset:')
		// Spaz.dump(off);

		// check horizontal position
		if (vp.x + vp.cx < off.left + $('#tooltip').width()) {
			// air.trace('horz over')
			$('#tooltip').css('left', parseInt($('#tooltip').css('left')) - ($('#tooltip').width() + 20));
			if ($('#tooltip').offset().left < 5) {
				$('#tooltip').css('left', 5);
			}
		}

		// check vertical position
		if(vp.y + vp.cy < off.top + $('#tooltip').height()) {
			// air.trace('vert over');
			$('#tooltip').css('top', parseInt($('#tooltip').css('top')) - ($('#tooltip').height() + 20));
			if ($('#tooltip').offset().top < 5) {
				$('#tooltip').css('top', 5);
			}
		}

		// air.trace('setting tooltip hide timeout');

		// air.trace('Tooltip hide delay:'+Spaz.Prefs.get('window-tooltiphidedelay'));

		Spaz_Tooltip_hideTimeout = setTimeout(Spaz.UI.hideTooltips, Spaz.Prefs.get('window-tooltiphidedelay'));
		// $('#tooltip').bind('mouseout', Spaz.UI.hideTooltips);
	}

}

/*
	I kinda stole this from the excellent jquery.tooltip
*/
Spaz_Tooltip.prototype.resetPosition = function() {
	var vp  = Spaz.UI.getViewport();
	var off = $('#tooltip').offset();

	// Spaz.dump(vp);
	// Spaz.dump(off);

	// Spaz.dump('reset width');
	// Spaz.dump("old width: "+$('#tooltip').width());

	var newWidth = vp.cx - off.left - 10;
	$('#tooltip').width( newWidth );

	// Spaz.dump("old width: "+newWidth);
};

<|endoftext|>


<commit_before>let languages = (function () {

// A global variable containing the current locale. Only written to within this module.
let globalLocale = 'en';

// A global variable containing the current text direction to enforce on portal-specific content.
// Only written to within this module.
let globalTextDirection = 'ltr';

// A special key that's added by the CENO Client to the standard id: string key-pair values in
// LANGUAGES.  The value LANGUAGES[TEXT_DIRECTION_KEY] will always be either 'ltr' or 'rtl'
// unless someone messes up the config/client.json file.
const TEXT_DIRECTION_KEY = '_direction_';

/**
 * Set the text content of a given element to some translated string.
 * @param {string} elemId - The id attribute of the element to access
 * @param {string} property - The name of the property of the element to set, e.g. textContent or innerHTML
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 * @param {string} stringId - The key in locale/all.json for the string to use
 * @return {boolean} true if the attribute could be set or defaulted to English, else false
 */
function setText(elemId, property, locale, stringId) {
  let elem = document.getElementById(elemId);
  if (elem && LANGUAGES.hasOwnProperty(locale) && LANGUAGES[locale].hasOwnProperty(stringId)) {
    elem[property] = LANGUAGES[locale][stringId];
  } else if (elem && LANGUAGES.en.hasOwnProperty(stringId)) {
    elem[property] = LANGUAGES.en[stringId];
  } else if (elem) {
    // For debugging purposes only
    elem[property] = 'INVALID STRING ID ' + stringId;
  } else {
    return false;
  }
  return true;
}

function setLocale(locale) {
  globalLocale = locale;
  document.getElementById('currentLocale').textContent = locale;
  let currentStatus = navigation.getPortalStatus();
  navigation.setConnectivityStatus(currentStatus);
  globalTextDirection = LANGUAGES[locale][TEXT_DIRECTION_KEY];
  // On every page, elements that can have the text direction changed will have the
  // class "directionToggles".
  let portalTexts = document.getElementsByClassName('directionToggles');
  console.log('Setting text directions to ' + globalTextDirection);
  for (let i = 0, len = portalTexts.length; i < len; i++) {
    portalTexts[i].style.direction = globalTextDirection;
  }
}

/**
 * Set all the visible text content on the channel selection page.
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 */
function setChannelText(locale) {
  setLocale(locale);
  if (!setText('chooseChannelHeader', 'textContent', locale, 'chooseChannel')) {
    console.log('Could not set "Choose Channel" header text.');
  }
}

/**
 * The articles page doesn't have any preset content, so we just set the global locale when
 * a new language is selected.
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 */
function setArticleText(locale) {
  setLocale(locale);
}

/**
 * Set all the visible text content on the main/index/home page of the portal.
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 */
function setIndexText(locale) {
  setLocale(locale);
  if (!setText('noMoreSurveillanceText', 'textContent', locale, 'noMoreSurveillance')) {
    console.log('Could not set "No More Surveillance" text.');
  }
  if (!setText('noMoreCensorshipText', 'textContent', locale, 'noMoreCensorship')) {
    console.log('Could not set "No More Censorship" text.');
  }
  if (!setText('whatNextHeader', 'textContent', locale, 'whatNext')) {
    console.log('Could not set "What Next" header text.');
  }
  if (!setText('browseChannelsHeader', 'textContent', locale, 'browseChannels')) {
    console.log('Could not set "Browse Channels" header text.');
  }
  if (!setText('browseChannelsParagraph', 'textContent', locale, 'browseChannelsDescription')) {
    console.log('Could not set "Browse Channels" paragraph text.');
  }
  if (!setText('requestSiteHeader', 'textContent', locale, 'requestSite')) {
    console.log('Could not set "Request a Site" header text.');
  }
  if (!setText('indexUrlSearch', 'placeholder', locale, 'enterUrl')) {
    console.log('Could not set "Enter a URL" input placeholder text.');
  }
  if (!setText('learnCENOHeader', 'textContent', locale, 'learnMore')) {
    console.log('Could not set "Learn More" Header text.');
  }
  if (!setText('learnCENOParagraph', 'textContent', locale, 'learnMoreDescription')) {
    console.log('Could not set "Learn More" paragraph text.');
  }
  if (!setText('tellMeMore', 'textContent', locale, 'learnMoreButton')) {
    console.log('Could not set "Learn More" button text.');
  }
  if (!setText('closeOverlayButton', 'textContent', locale, 'closeText')) {
    console.log('Could not set the "Close Overlay" button text.');
  }
}

function setAboutText(locale) {
  setLocale(locale);
  // Set the main header for the about page
  if (!setText('aboutHeaderMain', 'textContent', locale, 'about')) {
    console.log('Couldn\'t set the main header on the about page.');
  }
  // Set the text for all of the paragraphs and headers in the "About CENO" page.
  for (let i = 1; LANGUAGES[locale].hasOwnProperty('aboutHeader' + i); i++) {
    let id = 'aboutHeader' + i;
    if (!setText(id, 'textContent', locale, id)) {
      console.log('Could not set the header text for ' + id);
    }
  }
  for (let i = 1; LANGUAGES[locale].hasOwnProperty('aboutParagraph' + i); i++) {
    let id = 'aboutParagraph' + i;
    console.log('Trying to set text for ' + id);
    if (!setText(id, 'textContent', locale, id)) {
      console.log('Could not set the paragraph text for ' + id);
    }
  }
  // Set the text for the headers and paragraphs in the security Q&A section
  for (let i = 1; LANGUAGES[locale].hasOwnProperty('securitySubHeader' + i); i++) {
    let id = 'securitySubHeader' + i;
    if (!setText(id, 'textContent', locale, id)) {
      console.log('Could not set the header text for ' + id);
    }
  }
  for (let i = 1; LANGUAGES[locale].hasOwnProperty('securitySubParagraph' + i); i++) {
    let id = 'securitySubParagraph' + i;
    if (!setText(id, 'textContent', locale, id)) {
      console.log('Could not set the paragraphtext for ' + id);
    }
  }
}

/**
 * A helper function to set the text on whatever page we're on.
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 */
function setPortalText(locale) {
  setIndexText(locale);
  setChannelText(locale);
  setArticleText(locale);
  setAboutText(locale);
}

// When a language is selected, get its locale and reset the text on the page.
// TODO - Expand this to work on all pages.
let languageOptions = document.getElementsByClassName('languageSelect');
for (let i = 0, len = languageOptions.length; i < len; i++) {
  let option = languageOptions[i];
  option.addEventListener('click', () => {
    globalLocale = option.getAttribute('data-language');
    setPortalText(globalLocale);
  });
}

/**
 * For use by consumers of this module, get the currently selected locale.
 * @return {string} the current locale, like 'en' or 'fr'.
 */
function getLocale() {
  return globalLocale;
}

/**
 * For use by consumers of this module. Get the currently set text direction.
 * @return {string} the current text direction. Either 'ltr' or 'rtl'.
 */
function getTextDirection() {
  return globalTextDirection.toLowerCase();
}

return {
  setText,
  setChannelText,
  setArticleText,
  setIndexText,
  setAboutText,
  getLocale,
  getTextDirection,
};

})();
<commit_msg>Have the portal JS send a request to set the locale in the client when a language is selected<commit_after>let languages = (function () {

// A global variable containing the current locale. Only written to within this module.
let globalLocale = 'en';

// A global variable containing the current text direction to enforce on portal-specific content.
// Only written to within this module.
let globalTextDirection = 'ltr';

// A special key that's added by the CENO Client to the standard id: string key-pair values in
// LANGUAGES.  The value LANGUAGES[TEXT_DIRECTION_KEY] will always be either 'ltr' or 'rtl'
// unless someone messes up the config/client.json file.
const TEXT_DIRECTION_KEY = '_direction_';

// The endpoint to send POST requests to in order to set the locale in the client.
const SET_LOCALE_ENDPOINT = 'http://localhost:3090/locale';

/**
 * Set the text content of a given element to some translated string.
 * @param {string} elemId - The id attribute of the element to access
 * @param {string} property - The name of the property of the element to set, e.g. textContent or innerHTML
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 * @param {string} stringId - The key in locale/all.json for the string to use
 * @return {boolean} true if the attribute could be set or defaulted to English, else false
 */
function setText(elemId, property, locale, stringId) {
  let elem = document.getElementById(elemId);
  if (elem && LANGUAGES.hasOwnProperty(locale) && LANGUAGES[locale].hasOwnProperty(stringId)) {
    elem[property] = LANGUAGES[locale][stringId];
  } else if (elem && LANGUAGES.en.hasOwnProperty(stringId)) {
    elem[property] = LANGUAGES.en[stringId];
  } else if (elem) {
    // For debugging purposes only
    elem[property] = 'INVALID STRING ID ' + stringId;
  } else {
    return false;
  }
  return true;
}

function setLocale(locale) {
  globalLocale = locale;
  document.getElementById('currentLocale').textContent = locale;
  let currentStatus = navigation.getPortalStatus();
  navigation.setConnectivityStatus(currentStatus);
  globalTextDirection = LANGUAGES[locale][TEXT_DIRECTION_KEY];
  // On every page, elements that can have the text direction changed will have the
  // class "directionToggles".
  let portalTexts = document.getElementsByClassName('directionToggles');
  console.log('Setting text directions to ' + globalTextDirection);
  for (let i = 0, len = portalTexts.length; i < len; i++) {
    portalTexts[i].style.direction = globalTextDirection;
  }
}

/**
 * Set all the visible text content on the channel selection page.
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 */
function setChannelText(locale) {
  setLocale(locale);
  if (!setText('chooseChannelHeader', 'textContent', locale, 'chooseChannel')) {
    console.log('Could not set "Choose Channel" header text.');
  }
}

/**
 * The articles page doesn't have any preset content, so we just set the global locale when
 * a new language is selected.
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 */
function setArticleText(locale) {
  setLocale(locale);
}

/**
 * Set all the visible text content on the main/index/home page of the portal.
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 */
function setIndexText(locale) {
  setLocale(locale);
  if (!setText('noMoreSurveillanceText', 'textContent', locale, 'noMoreSurveillance')) {
    console.log('Could not set "No More Surveillance" text.');
  }
  if (!setText('noMoreCensorshipText', 'textContent', locale, 'noMoreCensorship')) {
    console.log('Could not set "No More Censorship" text.');
  }
  if (!setText('whatNextHeader', 'textContent', locale, 'whatNext')) {
    console.log('Could not set "What Next" header text.');
  }
  if (!setText('browseChannelsHeader', 'textContent', locale, 'browseChannels')) {
    console.log('Could not set "Browse Channels" header text.');
  }
  if (!setText('browseChannelsParagraph', 'textContent', locale, 'browseChannelsDescription')) {
    console.log('Could not set "Browse Channels" paragraph text.');
  }
  if (!setText('requestSiteHeader', 'textContent', locale, 'requestSite')) {
    console.log('Could not set "Request a Site" header text.');
  }
  if (!setText('indexUrlSearch', 'placeholder', locale, 'enterUrl')) {
    console.log('Could not set "Enter a URL" input placeholder text.');
  }
  if (!setText('learnCENOHeader', 'textContent', locale, 'learnMore')) {
    console.log('Could not set "Learn More" Header text.');
  }
  if (!setText('learnCENOParagraph', 'textContent', locale, 'learnMoreDescription')) {
    console.log('Could not set "Learn More" paragraph text.');
  }
  if (!setText('tellMeMore', 'textContent', locale, 'learnMoreButton')) {
    console.log('Could not set "Learn More" button text.');
  }
  if (!setText('closeOverlayButton', 'textContent', locale, 'closeText')) {
    console.log('Could not set the "Close Overlay" button text.');
  }
}

function setAboutText(locale) {
  setLocale(locale);
  // Set the main header for the about page
  if (!setText('aboutHeaderMain', 'textContent', locale, 'about')) {
    console.log('Couldn\'t set the main header on the about page.');
  }
  // Set the text for all of the paragraphs and headers in the "About CENO" page.
  for (let i = 1; LANGUAGES[locale].hasOwnProperty('aboutHeader' + i); i++) {
    let id = 'aboutHeader' + i;
    if (!setText(id, 'textContent', locale, id)) {
      console.log('Could not set the header text for ' + id);
    }
  }
  for (let i = 1; LANGUAGES[locale].hasOwnProperty('aboutParagraph' + i); i++) {
    let id = 'aboutParagraph' + i;
    console.log('Trying to set text for ' + id);
    if (!setText(id, 'textContent', locale, id)) {
      console.log('Could not set the paragraph text for ' + id);
    }
  }
  // Set the text for the headers and paragraphs in the security Q&A section
  for (let i = 1; LANGUAGES[locale].hasOwnProperty('securitySubHeader' + i); i++) {
    let id = 'securitySubHeader' + i;
    if (!setText(id, 'textContent', locale, id)) {
      console.log('Could not set the header text for ' + id);
    }
  }
  for (let i = 1; LANGUAGES[locale].hasOwnProperty('securitySubParagraph' + i); i++) {
    let id = 'securitySubParagraph' + i;
    if (!setText(id, 'textContent', locale, id)) {
      console.log('Could not set the paragraphtext for ' + id);
    }
  }
}

/**
 * A helper function to set the text on whatever page we're on.
 * @param {string} locale - The locale of the language to use, e.g. en or fr
 */
function setPortalText(locale) {
  setIndexText(locale);
  setChannelText(locale);
  setArticleText(locale);
  setAboutText(locale);
}

/**
 * Inform the CENO Client that the locale has changed so that it can remember the new
 * value and set the global CURRENT_LOCALE value every time a page is loaded.
 * @param {string} locale - The new locale to use, e.g. en or fr
 */
function setClientLocale(locale) {
  let xhr = new XMLHttpRequest();
  xhr.open('POST', SET_LOCALE_ENDPOINT, true);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.onload = () => {
    if (xhr.status === 200) { // OK
      let response = JSON.parse(xhr.responseText);
      if (response.success) {
        console.log('Successfully set locale to ' + locale);
      } else {
        console.log('Error: ' + response.error);
      }
    } else {
      console.log('Error setting locale. Status ' + xhr.status);
    }
  };
  xhr.onerror = () => console.log('Error setting locale.');
  xhr.send(JSON.stringify({
    locale: locale
  }));
}

// When a language is selected, get its locale, reset the text on the page to contain the
// strings translated for the selected locale, and inform the CENO Client what locale to switch
// to so that it will be automatically set on every page we visit afterwards.
let languageOptions = document.getElementsByClassName('languageSelect');
for (let i = 0, len = languageOptions.length; i < len; i++) {
  let option = languageOptions[i];
  option.addEventListener('click', () => {
    globalLocale = option.getAttribute('data-language');
    setPortalText(globalLocale);
    setClientLocale(globalLocale);
  });
}

/**
 * For use by consumers of this module, get the currently selected locale.
 * @return {string} the current locale, like 'en' or 'fr'.
 */
function getLocale() {
  return globalLocale;
}

/**
 * For use by consumers of this module. Get the currently set text direction.
 * @return {string} the current text direction. Either 'ltr' or 'rtl'.
 */
function getTextDirection() {
  return globalTextDirection.toLowerCase();
}

return {
  setText,
  setChannelText,
  setArticleText,
  setIndexText,
  setAboutText,
  getLocale,
  getTextDirection,
};

})();
<|endoftext|>


<commit_before>// File: chapter7/notesApp1SpecWithSpies.js

describe('ItemCtrl with spies', function() {
  beforeEach(module('notesApp1'));

  var ctrl, itemService;

  beforeEach(inject(function($controller, ItemService) {
    spyOn(ItemService, 'list').andCallThrough();
    itemService = ItemService;
    ctrl = $controller('ItemCtrl');
  }));

  it('should load mocked out items', function() {
    expect(itemService.list).toHaveBeenCalled();
    expect(itemService.list.callCount).toEqual(1);
    expect(ctrl.items).toEqual([
      {id: 1, label: 'Item 0'},
      {id: 2, label: 'Item 1'}
    ]);
  });
});
<commit_msg>Update notesApp1SpecWithSpies.js<commit_after>// File: chapter7/notesApp1SpecWithSpies.js

describe('ItemCtrl with spies', function() {
  beforeEach(module('notesApp1'));

  var ctrl, itemService;

  beforeEach(inject(function($controller, ItemService) {
    spyOn(ItemService, 'list').andCallThrough();
    // According to latest version of jasmine docs, andCallThrough() method has updated to and.callThrough()
    // http://jasmine.github.io/2.0/introduction.html#section-Spies:_and.callThrough
    // spyOn(ItemService, 'list').and.callThrough();
    itemService = ItemService;
    ctrl = $controller('ItemCtrl');
  }));

  it('should load mocked out items', function() {
    expect(itemService.list).toHaveBeenCalled();
    expect(itemService.list.callCount).toEqual(1);
    // According to latest version of jasmine docs, callCount property has updated to calls.count() method
    // http://jasmine.github.io/2.0/introduction.html#section-24
    // expect(itemService.list.calls.count()).toEqual(1);
    expect(ctrl.items).toEqual([
      {id: 1, label: 'Item 0'},
      {id: 2, label: 'Item 1'}
    ]);
  });
});
<|endoftext|>


<commit_before>/*
 * Embedded Galleries Slider
 * @module Slider
 * @author david.pisek@news.com.au
 */

var hammer = require('hammerjs');

function error (msg) {
  throw new Error(msg);
}

/**
 * Sets up a sliding gallery within the given element
 *
 * @constructor
 * @alias module:slider
 * @param {domElement} containerEl
 * @return {undefined}
 */
function Slider (containerEl) {

  if (!(containerEl instanceof HTMLElement)) {
    error('First parameter must be of type HTMLElement');
  }

  this.containerEl = containerEl;
  this.containerWidth = this.containerEl.getBoundingClientRect().width || container.offsetWidth;

  this.sliderEl = containerEl.children[0];
  this.sliderWidth = this.sliderEl.getBoundingClientRect().width || container.offsetWidth;

  this.interactiveEl = hammer(containerEl);

  this.currX = 0;
  this.prevDelta = 0;

  this._startListening();

  this._preventImageDrag();

}

/*
 * Default options
 */
Slider.defaults = {
  RESISTANCE_LEVEL: 15
};

/*
 * Listeners
 */
Slider.eventListeners = {

  onPanChangeX: function (e) {
    this.currX = this._calcCurrX(e.deltaX);
    this._slide();
  },
  onPanEnd: function (e) {

    if (this._leftBorderReached || this._rightBorderReached) {
      this._snapBack();
    }

    // reset delta - this is being used to calculate the x movement
    this.prevDelta = 0;

  }

};

/**
 * Brings the slider back into position after one of the horizontal borders
 * have been crossed
 *
 * @return {undefined}
 */
Slider.prototype._snapBack = function () {

  if (this._leftBorderReached) {
    this.currX = 0;
    this._leftBorderReached = false;
  }

  if (this._rightBorderReached) {
    this.currX = -(this.sliderWidth - this.containerWidth);
    this._rightBorderReached = false;
  }

  this._move();

};

/**
 * Binds all the event listeners needed for navigating the Gallery
 *
 * @private
 * @return {undefined}
 */
Slider.prototype._startListening = function () {

  this.interactiveEl.on('panleft panright', Slider.eventListeners.onPanChangeX.bind(this));
  this.interactiveEl.on('panend', Slider.eventListeners.onPanEnd.bind(this));

};

/**
 * Sliding Action
 *
 * @private
 * @return {undefined}
 */
Slider.prototype._slide = function () {

  var borderReached = this._borderReached(this.currX);

  switch(borderReached) {
    case 0:
      break;
    case -1:
      this._leftBorderReached = true;
      break;
    case 1:
      this._rightBorderReached = true;
  }

  this._move();

};

/**
 * Moves the slider to position x
 *
 * @private
 * @param x
 * @return {undefined}
 */
Slider.prototype._move = function () {

  this.sliderEl.style.webkitTransform = "translate3d("+ this.currX +"px,0,0)";

};

/**
 * Checks if either the right or left border has been reached
 * returns left: -1 right: 1 - otherwise 0
 *
 * @param x
 * @return {undefined}
 */
Slider.prototype._borderReached = function (x) {

  if (x > 0) {
    return -1;
  }

  if (Math.abs(x) + this.containerWidth > this.sliderWidth) {
    return 1;
  }

  return 0;

};

/**
 * Calculates the x value for the transition
 * adds resistance if either of the horizontal borders have been reached
 *
 * @private
 * @param deltaX
 * @param isFinal
 * @return {undefined}
 */
Slider.prototype._calcCurrX = function (deltaX) {

  var x, borderReached;

  x = this.currX + deltaX - this.prevDelta;
  borderReached = this._borderReached(x);

  if (borderReached === -1 || borderReached === 1) {
    x = this.currX + ((deltaX - this.prevDelta) / (Math.abs(deltaX) / this.sliderWidth + Slider.defaults.RESISTANCE_LEVEL));
  }

  this.prevDelta = deltaX;

  return x;

};

/**
 * Prevents images within the gallery from being dragged
 *
 * @private
 * @return {undefined}
 */
Slider.prototype._preventImageDrag = function () {

  var images = this.containerEl.querySelectorAll('img');

  function preventImageDrag (e) {
    return false;
  }

  [].slice.call(images).forEach(function (imgEl) {

    imgEl.ondragstart = preventImageDrag;

  });

};

module.exports = Slider;
<commit_msg>Slider refactor.<commit_after>/*
 * Embedded Galleries Slider
 * @module Slider
 * @author david.pisek@news.com.au
 */

var hammer = require('hammerjs');

function error (msg) {
    throw new Error(msg);
}

/**
 * Sets up a sliding gallery within the given element
 *
 * @constructor
 * @alias module:slider
 * @param {domElement} containerEl
 * @return {undefined}
 */
function Slider (containerEl) {

    if (!(containerEl instanceof HTMLElement)) {
        error('First parameter must be of type HTMLElement');
    }

    this.containerEl = containerEl;
    this.panEl = hammer(containerEl);
    this.sliderEl = containerEl.children[0];

    this.currX = 0;
    this.nextX = 0;
    this.prevDelta = 0;

    this._setWidths();
    this._startListening();
    this._preventImageDrag();

}

/*
 * Default options
 */
Slider.defaults = {
    RESISTANCE_LEVEL: 15
};

/*
 * Listeners
 */
Slider.eventListeners = {

    onPanChangeX: function (e) {
        this._setNextX(e.deltaX);
        this._moveToNextX();
    },
    onPanEnd: function (e) {

        if (this._leftBorderReached || this._rightBorderReached) {
            this._snapBack();
        }

        // reset delta - this is being used to calculate the x movement
        this.prevDelta = 0;

    }

};

/**
 * Calculates and sets the widths of the container and slider elements
 *
 * @return {undefined}
 */
Slider.prototype._setWidths = function () {

    this.containerWidth = this.containerEl.getBoundingClientRect().width || this.containerEl.offsetWidth;
    this.sliderWidth = this.sliderEl.getBoundingClientRect().width || this.sliderWidth.offsetWidth;

};

/**
 * Brings the slider back into position after one of the horizontal borders
 * have been crossed
 *
 * @return {undefined}
 */
Slider.prototype._snapBack = function () {

    if (this._leftBorderReached) {
        this.nextX = 0;
    }

    // if container is bigger than slider no snapping to right edge
    if (this._rightBorderReached) {
        this.nextX = -(this.sliderWidth - this.containerWidth);
    }

    this._resetBorderReached();
    this._moveToNextX();

};

/**
 *  Resets border reachead booleans
 *
 * @return {undefined}
 */
Slider.prototype._resetBorderReached = function () {
    this._rightBorderReached = false;
    this._leftBorderReached = false;
};

/**
 * Binds all the event listeners needed for navigating the Gallery
 *
 * @private
 * @return {undefined}
 */
Slider.prototype._startListening = function () {

    window.onresize = this._setWidths.bind(this);

    this.panEl.on('panleft panright', Slider.eventListeners.onPanChangeX.bind(this));
    this.panEl.on('panend', Slider.eventListeners.onPanEnd.bind(this));

};

/**
 * Moves the slider to position x
 *
 * @private
 * @param x
 * @return {undefined}
 */
Slider.prototype._moveToNextX = function () {

    this.sliderEl.style.webkitTransform = "translate3d("+ this.nextX +"px,0,0)";
    this.currX = this.nextX;

};

/**
 * Checks if either the right or left border has been reached
 *
 * @param x
 * @return {undefined}
 */
Slider.prototype._checkIfBorderReached = function (nextX) {

        // if the container is bigger than the slider then never scroll to right
        if(this.containerWidth > this.sliderWidth || nextX > 0) {
            this._leftBorderReached = true;
            return true;
        }

        if(Math.abs(nextX) + this.containerWidth > this.sliderWidth) {
            this._rightBorderReached = true;
            return true;
        }

        return false;

};

/**
 * Calculates the x value for the transition
 * adds resistance if either of the horizontal borders have been reached
 *
 * @private
 * @param deltaX
 * @param isFinal
 * @return {undefined}
 */
Slider.prototype._setNextX = function (deltaX) {

    var nextX, borderReached;

    nextX = this.currX + deltaX - this.prevDelta;

    borderReached = this._checkIfBorderReached(nextX);

    if (borderReached) {
        nextX = this.currX + ((deltaX - this.prevDelta) / (Math.abs(deltaX) / this.sliderWidth + Slider.defaults.RESISTANCE_LEVEL));
    }

    this.prevDelta = deltaX;
    this.nextX = nextX;

};

/**
 * Prevents images within the gallery from being dragged
 *
 * @private
 * @return {undefined}
 */
Slider.prototype._preventImageDrag = function () {

    var images = this.containerEl.querySelectorAll('img');

    function preventImageDrag (e) {
        return false;
    }

    [].slice.call(images).forEach(function (imgEl) {

        imgEl.ondragstart = preventImageDrag;

    });

};

module.exports = Slider;
<|endoftext|>


<commit_before>/*
 * jQuery MultiSelect UI Widget Filtering Plugin 1.2
 * Copyright (c) 2011 Eric Hynds
 *
 * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
 *
 * Depends:
 *   - jQuery UI MultiSelect widget
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
*/
(function($){
	var rEscape = /[\-\[\]{}()*+?.,\\^$|#\s]/g;

	$.widget("ech.multiselectfilter", {

		options: {
			label: "Filter:",
			width: null, /* override default width set in css file (px). null will inherit */
			placeholder: "Enter keywords"
		},

		_create: function(){
			var self = this,
				opts = this.options,
				instance = (this.instance = $(this.element).data("multiselect")),

				// store header; add filter class so the close/check all/uncheck all links can be positioned correctly
				header = (this.header = instance.menu.find(".ui-multiselect-header").addClass("ui-multiselect-hasfilter")),

				// wrapper elem
				wrapper = (this.wrapper = $('
'+(opts.label.length ? opts.label : '')+'<input placeholder="'+opts.placeholder+'" type="search"' + (/\d/.test(opts.width) ? 'style="width:'+opts.width+'px"' : '') + ' />
').prependTo( this.header ));

			// reference to the actual inputs
			this.inputs = instance.menu.find('input[type="checkbox"], input[type="radio"]');

			// build the input box
			this.input = wrapper
			.find("input")
			.bind({
				keydown: function( e ){
					// prevent the enter key from submitting the form / closing the widget
					if( e.which === 13 ){
						e.preventDefault();
					}
				},
				keyup: $.proxy(self._handler, self),
				click: $.proxy(self._handler, self)
			});

			// cache input values for searching
			this.updateCache();

			// rewrite internal _toggleChecked fn so that when checkAll/uncheckAll is fired,
			// only the currently filtered elements are checked
			instance._toggleChecked = function(flag, group){
				var $inputs = (group && group.length) ?
						group :
						this.labels.find('input'),

					_self = this,

					// do not include hidden elems if the menu isn't open.
					selector = self.instance._isOpen ?
						":disabled, :hidden" :
						":disabled";

				$inputs = $inputs.not( selector ).each(this._toggleCheckbox('checked', flag));

				// update text
				this.update();

				// figure out which option tags need to be selected
				var values = $inputs.map(function(){
					return this.value;
				}).get();

				// select option tags
				this.element
					.find('option')
					.filter(function(){
						if( !this.disabled && $.inArray(this.value, values) > -1 ){
							_self._toggleCheckbox('selected', flag).call( this );
						}
					});
			};

			// rebuild cache when multiselect is updated
			$(document).bind("multiselectrefresh", function(){
				self.updateCache();
				self._handler();
			});
		},

		// thx for the logic here ben alman
		_handler: function( e ){
			var term = $.trim( this.input[0].value.toLowerCase() ),

				// speed up lookups
				rows = this.rows, inputs = this.inputs, cache = this.cache;

			if( !term ){
				rows.show();
			} else {
				rows.hide();

				var regex = new RegExp(term.replace(rEscape, "\\$&"), 'gi');

				this._trigger( "filter", e, $.map(cache, function(v,i){
					if( v.search(regex) !== -1 ){
						rows.eq(i).show();
						return inputs.get(i);
					}

					return null;
				}));
			}

			// show/hide optgroups
			this.instance.menu.find(".ui-multiselect-optgroup-label").each(function(){
				var $this = $(this);
				$this[ $this.nextUntil('.ui-multiselect-optgroup-label').filter(':visible').length ? 'show' : 'hide' ]();
			});
		},

		updateCache: function(){
			// each list item
			this.rows = this.instance.menu.find(".ui-multiselect-checkboxes li:not(.ui-multiselect-optgroup-label)");

			// cache
			this.cache = this.element.children().map(function(){
				var self = $(this);

				// account for optgroups
				if( this.tagName.toLowerCase() === "optgroup" ){
					self = self.children();
				}

				// see _create() in jquery.multiselect.js
				if( !self.val().length ){
					return null;
				}

				return self.map(function(){
					return this.innerHTML.toLowerCase();
				}).get();
			}).get();
		},

		widget: function(){
			return this.wrapper;
		},

		destroy: function(){
			$.Widget.prototype.destroy.call( this );
			this.input.val('').trigger("keyup");
			this.wrapper.remove();
		}
	});
})(jQuery);
<commit_msg>do not exclude options with empty values from the cache. fixes #105<commit_after>/*
 * jQuery MultiSelect UI Widget Filtering Plugin 1.2
 * Copyright (c) 2011 Eric Hynds
 *
 * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
 *
 * Depends:
 *   - jQuery UI MultiSelect widget
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
*/
(function($){
	var rEscape = /[\-\[\]{}()*+?.,\\^$|#\s]/g;

	$.widget("ech.multiselectfilter", {

		options: {
			label: "Filter:",
			width: null, /* override default width set in css file (px). null will inherit */
			placeholder: "Enter keywords"
		},

		_create: function(){
			var self = this,
				opts = this.options,
				instance = (this.instance = $(this.element).data("multiselect")),

				// store header; add filter class so the close/check all/uncheck all links can be positioned correctly
				header = (this.header = instance.menu.find(".ui-multiselect-header").addClass("ui-multiselect-hasfilter")),

				// wrapper elem
				wrapper = (this.wrapper = $('
'+(opts.label.length ? opts.label : '')+'<input placeholder="'+opts.placeholder+'" type="search"' + (/\d/.test(opts.width) ? 'style="width:'+opts.width+'px"' : '') + ' />
').prependTo( this.header ));

			// reference to the actual inputs
			this.inputs = instance.menu.find('input[type="checkbox"], input[type="radio"]');

			// build the input box
			this.input = wrapper
			.find("input")
			.bind({
				keydown: function( e ){
					// prevent the enter key from submitting the form / closing the widget
					if( e.which === 13 ){
						e.preventDefault();
					}
				},
				keyup: $.proxy(self._handler, self),
				click: $.proxy(self._handler, self)
			});

			// cache input values for searching
			this.updateCache();

			// rewrite internal _toggleChecked fn so that when checkAll/uncheckAll is fired,
			// only the currently filtered elements are checked
			instance._toggleChecked = function(flag, group){
				var $inputs = (group && group.length) ?
						group :
						this.labels.find('input'),

					_self = this,

					// do not include hidden elems if the menu isn't open.
					selector = self.instance._isOpen ?
						":disabled, :hidden" :
						":disabled";

				$inputs = $inputs.not( selector ).each(this._toggleCheckbox('checked', flag));

				// update text
				this.update();

				// figure out which option tags need to be selected
				var values = $inputs.map(function(){
					return this.value;
				}).get();

				// select option tags
				this.element
					.find('option')
					.filter(function(){
						if( !this.disabled && $.inArray(this.value, values) > -1 ){
							_self._toggleCheckbox('selected', flag).call( this );
						}
					});
			};

			// rebuild cache when multiselect is updated
			$(document).bind("multiselectrefresh", function(){
				self.updateCache();
				self._handler();
			});
		},

		// thx for the logic here ben alman
		_handler: function( e ){
			var term = $.trim( this.input[0].value.toLowerCase() ),

				// speed up lookups
				rows = this.rows, inputs = this.inputs, cache = this.cache;

			if( !term ){
				rows.show();
			} else {
				rows.hide();

				var regex = new RegExp(term.replace(rEscape, "\\$&"), 'gi');

				this._trigger( "filter", e, $.map(cache, function(v,i){
					if( v.search(regex) !== -1 ){
						rows.eq(i).show();
						return inputs.get(i);
					}

					return null;
				}));
			}

			// show/hide optgroups
			this.instance.menu.find(".ui-multiselect-optgroup-label").each(function(){
				var $this = $(this);
				$this[ $this.nextUntil('.ui-multiselect-optgroup-label').filter(':visible').length ? 'show' : 'hide' ]();
			});
		},

		updateCache: function(){
			// each list item
			this.rows = this.instance.menu.find(".ui-multiselect-checkboxes li:not(.ui-multiselect-optgroup-label)");

			// cache
			this.cache = this.element.children().map(function(){
				var self = $(this);

				// account for optgroups
				if( this.tagName.toLowerCase() === "optgroup" ){
					self = self.children();
				}

				return self.map(function(){
					return this.innerHTML.toLowerCase();
				}).get();
			}).get();
		},

		widget: function(){
			return this.wrapper;
		},

		destroy: function(){
			$.Widget.prototype.destroy.call( this );
			this.input.val('').trigger("keyup");
			this.wrapper.remove();
		}
	});
})(jQuery);
<|endoftext|>


<commit_before>'use strict';
/* User module */

//Controller for Excel file upload
// @ngInject
var UploadObservationsCtrl = function($scope, $http, NpolarApiSecurity) {
    $scope.security = NpolarApiSecurity;

     $scope.filesChanged = function(elm){
        $scope.files=elm.files;
        $scope.$apply();
     };

     $scope.upload = function(elm) {

        var files = $scope.files;
        var i,f;

        for (i = 0, f = files[i]; i !== files.length; ++i) {
          var reader = new FileReader();

            reader.onload = (function(f){
              //var fileName = theFile.name;
              return function(e){
                 var data = e.target.result;

                 var workbook = XLSX.read(data, {type: 'binary'});
                  //Read first workbook
                 var sheet_name_list = workbook.SheetNames;

                 //Remove the two helper sheets from sheet list
                 removeVal(sheet_name_list, 'About the Form');
                 removeVal(sheet_name_list, 'Species name');

                 sheet_name_list.forEach(function(y) { // iterate through sheets
                    var worksheet = workbook.Sheets[y];
                    var entry = {}, exped = {};

                    for (var q in worksheet) {
                    // all keys that do not begin with "!" correspond to cell addresses
                    //y is heading text, z is cellno, worksheet[z].v is cell content

                           //Expedition
                           if (q ==="K2") { exped.other_info = worksheet[q].v;}
                           if (q ==="K3") { exped.contact_info = worksheet[q].v;}
                           if (q ==="K4") { exped.organisation = worksheet[q].v;}
                           if (q ==="K5") { var start_d = getJsDateFromExcel(worksheet[q].v); exped.start_date = start_d;}
                           if (q ==="K6") { var end_d = getJsDateFromExcel(worksheet[q].v); exped.end_date = end_d;}
                           if (q ==="K7") { exped.platform = worksheet[q].v;}
                    }

                     //A few more values applied to each entry
                    entry.recorded_by = (NpolarApiSecurity.getUser()).name;
                    entry.created_by = (NpolarApiSecurity.getUser()).name;
                     var date2 = new Date();
                    entry.created = date2.toISOString().substring(0,10) + 'T00:00:00Z';

                    //Excel file
                    var excel = {};
                    excel.filename = f.name;
                    excel['content-type'] =  f.type;
                    excel['content-size'] = f.size;

                    for (var z in worksheet) {
                           var num = z.substring(1);
                          // console.log(num, z, worksheet["A"+num]);
                          //Excel lines start at 20 so check bigger than 19
                           if ((num > 19) && (worksheet["A"+num] !== undefined) && (typeof worksheet["A"+num].v === "number" )) {

                              if (z === ("A"+num)) { var event_d = getJsDateFromExcel(worksheet[z].v);
                               exped.event_date = event_d;}
                              if (z === ("B"+num)) { entry.latitude = worksheet[z].v;}
                              if (z === ("C"+num)) { entry.longitude = worksheet[z].v;}
                              if (z === ("D"+num)) { worksheet[z].v === "(select or write placename)" ? (entry.locality = "") : (entry.locality = worksheet[z].v);}
                              if (z === ("E"+num)) { worksheet[z].v === "(select species)" ? (entry.species = "") : (entry.species = worksheet[z].v);}
                              if (z === ("F"+num)) { entry.adult_m = worksheet[z].v;}
                              if (z === ("G"+num)) { entry.adult_f = worksheet[z].v;}
                              if (z === ("H"+num)) { entry.adult = worksheet[z].v;}
                              if (z === ("I"+num)) { entry.sub_adult = worksheet[z].v;}
                              if (z === ("J"+num)) {  worksheet[z].v === "(select condition)" ? (entry.polar_bear_condition = "") : (entry.polar_bear_condition = worksheet[z].v);}
                              if (z === ("K"+num)) { entry.cub_calf_pup = worksheet[z].v;}
                              if (z === ("L"+num)) { worksheet[z].v === "(select years)" ? (entry.bear_cubs = "") : (entry.bear_cubs = worksheet[z].v);}
                              if (z === ("M"+num)) { entry.unidentified = worksheet[z].v;}
                              if (z === ("N"+num)) { entry.dead_alive = worksheet[z].v;}
                              if (z === ("O"+num)) { entry.total = worksheet[z].v;}
                              if (z === ("P"+num)) { worksheet[z].v === "(select habitat)" ? (entry.habitat = "") : (entry.habitat = worksheet[z].v);}
                              if (z === ("Q"+num)) { entry.occurrence_remarks= worksheet[z].v;}

                              //Need to add a timestamp to filename to ensure uniqueness
                              //which is local time now in iso8601
                              var date = new Date();
                               excel.timestamp =  date.toISOString().replace(/\.[0-9]{3}/g,"");
                                //console.log(excel.timestamp);

                                //Add subobjects to main object entry
                                entry.excelfile =  excel;
                                entry.expedition =  exped;

                                //Save entry, P is last letter
                                if (z.substring(0,1) === "P") {
                                   console.log(z, JSON.stringify(entry));
                                }

                       } //typeof
                  } //For -worksheet

                  });
              };
            })(f);
          reader.readAsBinaryString(f);

   }
};
};

function getJsDateFromExcel(excelDate) {

  // JavaScript dates represents time
  // since the Unix epoch (January 1, 1970) example: new Date(12312512312);

  // 1. Subtract number of days between Jan 1, 1900 and Jan 1, 1970, plus 1 (Google "excel leap year bug")
  // 2. Convert to milliseconds.
  //Next leap year 2016

  var date = new Date((excelDate - (25567+2))*86400*1000);

  //Browser that does not have toISOString
  if ( !Date.prototype.toISOString ) {
  ( function() {

    function pad(number) {
      var r = String(number);
      if ( r.length === 1 ) {
        r = '0' + r;
      }
      return r;
    }

    Date.prototype.toISOString = function() {
      return this.getUTCFullYear() +
         '-' + pad( this.getUTCMonth() + 1 ) +
         '-' + pad( this.getUTCDate() ) +
         'T' + pad( this.getUTCHours() ) +
         ':' + pad( this.getUTCMinutes() ) +
         ':' + pad( this.getUTCSeconds() ) +
         'Z';
    };

  }() ); }
 else {//Get rid of date extension
  return date.toISOString().replace(/\.[0-9]{3}/g,"");
}
}

//Pops a value by name off the workbook array
function removeVal(arr) {
    var what, a = arguments, L = a.length, ax;
    while (L > 1 && arr.length) {
        what = a[--L];
        while ((ax= arr.indexOf(what)) !== -1) {
            arr.splice(ax, 1);
        }
    }
    return arr;
}

module.exports = UploadObservationsCtrl;<commit_msg>IE excel upload error<commit_after>'use strict';
/* User module */

//Controller for Excel file upload
// @ngInject
var UploadObservationsCtrl = function($scope, $http, NpolarApiSecurity) {
    $scope.security = NpolarApiSecurity;

     $scope.filesChanged = function(elm){
        $scope.files=elm.files;
        $scope.$apply();
     };

     $scope.upload = function(elm) {

        var files = $scope.files;
        var i,f;
        var rABS = typeof FileReader !== "undefined" && typeof FileReader.prototype !== "undefined" && typeof FileReader.prototype.readAsBinaryString !== "undefined";

        for (i = 0, f = files[i]; i !== files.length; ++i) {
          var reader = new FileReader();

            reader.onload = (function(f){
              //var fileName = theFile.name;
              return function(e){
                 var data = e.target.result;

                 var workbook = XLSX.read(data, {type: 'binary'});
                  //Read first workbook
                 var sheet_name_list = workbook.SheetNames;

                 //Remove the two helper sheets from sheet list
                 removeVal(sheet_name_list, 'About the Form');
                 removeVal(sheet_name_list, 'Species name');

                 sheet_name_list.forEach(function(y) { // iterate through sheets
                    var worksheet = workbook.Sheets[y];
                    var entry = {}, exped = {};

                    for (var q in worksheet) {
                    // all keys that do not begin with "!" correspond to cell addresses
                    //y is heading text, z is cellno, worksheet[z].v is cell content

                           //Expedition
                           if (q ==="K2") { exped.other_info = worksheet[q].v;}
                           if (q ==="K3") { exped.contact_info = worksheet[q].v;}
                           if (q ==="K4") { exped.organisation = worksheet[q].v;}
                           if (q ==="K5") { var start_d = getJsDateFromExcel(worksheet[q].v); exped.start_date = start_d;}
                           if (q ==="K6") { var end_d = getJsDateFromExcel(worksheet[q].v); exped.end_date = end_d;}
                           if (q ==="K7") { exped.platform = worksheet[q].v;}
                    }

                     //A few more values applied to each entry
                    entry.recorded_by = (NpolarApiSecurity.getUser()).name;
                    entry.created_by = (NpolarApiSecurity.getUser()).name;
                     var date2 = new Date();
                    entry.created = date2.toISOString().substring(0,10) + 'T00:00:00Z';

                    //Excel file
                    var excel = {};
                    excel.filename = f.name;
                    excel['content-type'] =  f.type;
                    excel['content-size'] = f.size;

                    for (var z in worksheet) {
                           var num = z.substring(1);
                          // console.log(num, z, worksheet["A"+num]);
                          //Excel lines start at 20 so check bigger than 19
                           if ((num > 19) && (worksheet["A"+num] !== undefined) && (typeof worksheet["A"+num].v === "number" )) {

                              if (z === ("A"+num)) { var event_d = getJsDateFromExcel(worksheet[z].v);
                               exped.event_date = event_d;}
                              if (z === ("B"+num)) { entry.latitude = worksheet[z].v;}
                              if (z === ("C"+num)) { entry.longitude = worksheet[z].v;}
                              if (z === ("D"+num)) { worksheet[z].v === "(select or write placename)" ? (entry.locality = "") : (entry.locality = worksheet[z].v);}
                              if (z === ("E"+num)) { worksheet[z].v === "(select species)" ? (entry.species = "") : (entry.species = worksheet[z].v);}
                              if (z === ("F"+num)) { entry.adult_m = worksheet[z].v;}
                              if (z === ("G"+num)) { entry.adult_f = worksheet[z].v;}
                              if (z === ("H"+num)) { entry.adult = worksheet[z].v;}
                              if (z === ("I"+num)) { entry.sub_adult = worksheet[z].v;}
                              if (z === ("J"+num)) {  worksheet[z].v === "(select condition)" ? (entry.polar_bear_condition = "") : (entry.polar_bear_condition = worksheet[z].v);}
                              if (z === ("K"+num)) { entry.cub_calf_pup = worksheet[z].v;}
                              if (z === ("L"+num)) { worksheet[z].v === "(select years)" ? (entry.bear_cubs = "") : (entry.bear_cubs = worksheet[z].v);}
                              if (z === ("M"+num)) { entry.unidentified = worksheet[z].v;}
                              if (z === ("N"+num)) { entry.dead_alive = worksheet[z].v;}
                              if (z === ("O"+num)) { entry.total = worksheet[z].v;}
                              if (z === ("P"+num)) { worksheet[z].v === "(select habitat)" ? (entry.habitat = "") : (entry.habitat = worksheet[z].v);}
                              if (z === ("Q"+num)) { entry.occurrence_remarks= worksheet[z].v;}

                              //Need to add a timestamp to filename to ensure uniqueness
                              //which is local time now in iso8601
                              var date = new Date();
                               excel.timestamp =  date.toISOString().replace(/\.[0-9]{3}/g,"");
                                //console.log(excel.timestamp);

                                //Add subobjects to main object entry
                                entry.excelfile =  excel;
                                entry.expedition =  exped;

                                //Save entry, P is last letter
                                if (z.substring(0,1) === "P") {
                                   console.log(z, JSON.stringify(entry));
                                }

                       } //typeof
                  } //For -worksheet

                  });
              };
            })(f);
            if (rABS) { reader.readAsBinaryString(f); }
            else {reader.readAsArrayBuffer(f);}

   }
};
};

function getJsDateFromExcel(excelDate) {

  // JavaScript dates represents time
  // since the Unix epoch (January 1, 1970) example: new Date(12312512312);

  // 1. Subtract number of days between Jan 1, 1900 and Jan 1, 1970, plus 1 (Google "excel leap year bug")
  // 2. Convert to milliseconds.
  //Next leap year 2016

  var date = new Date((excelDate - (25567+2))*86400*1000);

  //Browser that does not have toISOString
  if ( !Date.prototype.toISOString ) {
  ( function() {

    function pad(number) {
      var r = String(number);
      if ( r.length === 1 ) {
        r = '0' + r;
      }
      return r;
    }

    Date.prototype.toISOString = function() {
      return this.getUTCFullYear() +
         '-' + pad( this.getUTCMonth() + 1 ) +
         '-' + pad( this.getUTCDate() ) +
         'T' + pad( this.getUTCHours() ) +
         ':' + pad( this.getUTCMinutes() ) +
         ':' + pad( this.getUTCSeconds() ) +
         'Z';
    };

  }() ); }
 else {//Get rid of date extension
  return date.toISOString().replace(/\.[0-9]{3}/g,"");
}
}

//Pops a value by name off the workbook array
function removeVal(arr) {
    var what, a = arguments, L = a.length, ax;
    while (L > 1 && arr.length) {
        what = a[--L];
        while ((ax= arr.indexOf(what)) !== -1) {
            arr.splice(ax, 1);
        }
    }
    return arr;
}

module.exports = UploadObservationsCtrl;<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';

const PropTypes = React.PropTypes;

class Rect extends React.Component {
  componentDidMount() {
    this.transitionRect(this.props);
  }

  componentWillUpdate(nextProps) {
    this.transitionRect(nextProps);
  }

  transitionRect(props) {
    let {transitionDuration, transform} = props;

    let el = ReactDOM.findDOMNode(this);
    d3.select(el)
      .transition()
      .duration(transitionDuration)
      .ease('linear')
      .attr('transform', transform);
  }

  render() {
    let {width, height, x, y, fill, className} = this.props;

    return (
      <rect
        width={width}
        height={height}
        x={x}
        y={y}
        fill={fill}
        className={className} />
    );
  }
}

Rect.propTypes = {
  width: PropTypes.number,
  height: PropTypes.number,
  x: PropTypes.number,
  y: PropTypes.number,
  fill: PropTypes.string,
  className: PropTypes.string,
  transitionDuration: PropTypes.number,
  transform: PropTypes.string,
  key: PropTypes.any
};

module.exports = Rect;
<commit_msg>So much nitting I became a grandma<commit_after>import React from 'react';
import ReactDOM from 'react-dom';

const PropTypes = React.PropTypes;

class Rect extends React.Component {
  componentDidMount() {
    this.transitionRect(this.props);
  }

  componentWillUpdate(nextProps) {
    this.transitionRect(nextProps);
  }

  transitionRect(props) {
    let {transitionDuration, transform} = props;
    let el = ReactDOM.findDOMNode(this);

    d3.select(el)
      .transition()
      .duration(transitionDuration)
      .ease('linear')
      .attr('transform', transform);
  }

  render() {
    let {width, height, x, y, fill, className} = this.props;

    return (
      <rect
        width={width}
        height={height}
        x={x}
        y={y}
        fill={fill}
        className={className} />
    );
  }
}

Rect.propTypes = {
  width: PropTypes.number,
  height: PropTypes.number,
  x: PropTypes.number,
  y: PropTypes.number,
  fill: PropTypes.string,
  className: PropTypes.string,
  transitionDuration: PropTypes.number,
  transform: PropTypes.string,
  key: PropTypes.any
};

module.exports = Rect;
<|endoftext|>