<commit_before>// InstantClick 1.1
// (C) 2014 Alexandre Dieulot
// http://instantclick.io/license.html

var InstantClick = function(document, location) {
	var currentLocationWithoutHash
	var pHistory = {} // short for "preloadHistory"
	var p = {} // short for "preloads"
	var supported = 'pushState' in history
	var useBlacklist
	var listeners = {change: []}

	function removeHash(url) {
		var index = url.indexOf('#')
		if (index == -1) {
			return url
		}
		return url.substr(0, index)
	}

	function getLinkTarget(target) {
		while (target.nodeName != 'A') {
			target = target.parentNode
		}
		return target
	}

	function on(type, listener) {
		listeners[type].push(listener)
	}

	function triggerPageEvent(type) {
		for (var i = 0; i < listeners[type].length; i++) {
			listeners[type][i]()
		}
	}

	function debug() {
		return {
			currentLocationWithoutHash: currentLocationWithoutHash,
			p: p,
			pHistory: pHistory,
			supported: supported,
			useBlacklist: useBlacklist
		}
	}

	function instantanize(isInitializing) {
		var as = document.getElementsByTagName('a'), a, domain = location.protocol + '//' + location.host
		for (var i = as.length - 1; i >= 0; i--) {
			a = as[i]
			if (a.target || // target="_blank" etc.
				a.href.indexOf(domain + '/') != 0 || // another domain (or no href attribute)
				a.href.indexOf('#') > -1 && removeHash(a.href) == currentLocationWithoutHash || // link to an anchor
				(useBlacklist ? a.hasAttribute('data-no-instant') : !a.hasAttribute('data-instant'))) {
				continue
			}
			a.addEventListener('mouseover', queue)
			a.addEventListener('click', click)
		}
		if (!isInitializing) {
			var scripts = document.getElementsByTagName('script'), script, copy, parentNode, nextSibling
			for (i = 0, j = scripts.length; i < j; i++) {
				script = scripts[i]
				if (script.hasAttribute('data-no-instant')) {
					continue
				}
				copy = document.createElement('script')
				if (script.src) {
					copy.src = script.src
				}
				if (script.innerHTML) {
					copy.innerHTML = script.innerHTML
				}
				parentNode = script.parentNode
				nextSibling = script.nextSibling
				parentNode.removeChild(script)
				parentNode.insertBefore(copy, nextSibling)
			}
		}
		triggerPageEvent('change')
	}

	function queue(e) {
		var a = getLinkTarget(e.target)
		a.addEventListener('mouseout', mouseout)
		preload(a.href)
	}

	function preload(url) {
		if ((p.isPreloading && url == p.url) || (p.isPreloading && p.isWaitingForCompletion)) {
			return
		}
		p.isPreloading = true
		p.isWaitingForCompletion = false
		p.url = url
		p.body = false
		p.hasBody = true
		p.timingStart = +new Date
		p.timing = false
		p.xhr.open('GET', url)
		p.xhr.send()
	}

	function readystatechange(e) {
		if (p.xhr.readyState < 4) {
			return
		}

		var text = p.xhr.responseText

		p.timing = +new Date - p.timingStart
		// Note: For debugging (`InstantClick.debug`), we know the page
		// has been preloaded if `p.timing` isn't false.

		var titleIndex = text.indexOf('<title')
		if (titleIndex > -1) {
			p.title = text.substr(text.indexOf('>', titleIndex) + 1)
			p.title = p.title.substr(0, p.title.indexOf('</title'))
		}

		var bodyIndex = text.indexOf('<body')
		if (bodyIndex > -1) {
			p.body = text.substr(text.indexOf('>', bodyIndex) + 1)
			var closingIndex = p.body.indexOf('</body')
			if (closingIndex > -1) {
				p.body = p.body.substr(0, closingIndex)
			}

			var urlWithoutHash = removeHash(p.url)
			pHistory[urlWithoutHash] = {
				body: p.body,
				title: p.title,
				scrollY: urlWithoutHash in pHistory ? pHistory[urlWithoutHash].scrollY : 0
			}
		}
		else {
			p.hasBody = false
		}
		/* We're only getting the body element's innerHTML, not the
		   element's attributes such as class etc.
		   From a superficial look into it, it seems Turbolinks DOMify
		   the body element so it's able to also get classes etc., and
		   doesn't require an explicit body tag in the html. This
		   should be explored later. */

		if (p.isWaitingForCompletion) {
			display(p.url)
		}
	}

	function click(e) {
		if (e.which > 1 || e.metaKey || e.ctrlKey) { // Opening in new tab
			return
		}
		e.preventDefault()
		display(getLinkTarget(e.target).href)
	}

	function display(url) {
		if (!p.isPreloading || (p.isPreloading && p.isWaitingForCompletion)) {
			/* If the page isn't preloaded, it means
			   the user has focused on a link (with his Tab
			   key) and then pressed Return, which triggered a click.
			   Because very few people do this, it isn't worth handling this
			   case and preloading on focus (also, focussing on a link
			   doesn't mean it's likely that you'll "click" on it), so we just
			   redirect them when they "click".

			   If the page is waiting for completion, the user clicked twice
			   while the page was preloading.
			   Two possibilities:
			   1) He clicks on the same link again, either because it's slow
			      to load (there's no browser loading indicator with
			      InstantClick, so he might think his click hasn't registered
			      if the page isn't loading fast enough) or because he has
			      a habit of double clicking on the web;
			   2) He clicks on another link.

			   In the first case, we redirect him (send him to the page the old
			   way) so that he can have the browser's loading indicator back.
			   In the second case, we redirect him because we haven't preloaded
			   that link, since we were already preloading the last one.

			   Determining if it's a double click might be overkill as there is
			   (hopefully) not that many people that double click on the web.
			   Fighting against the perception that the page is stuck is
			   interesting though, a seemingly good way to do that would be to
			   later incorporate a progress bar.
			*/

			location.href = url
			return
		}
		if (!p.hasBody) {
			location.href = p.url
			return
		}
		if (!p.body) {
			p.isWaitingForCompletion = true
			return
		}
		pHistory[currentLocationWithoutHash].scrollY = scrollY
		p.isPreloading = false
		p.isWaitingForCompletion = false
		document.body.innerHTML = p.body
		document.title = p.title
		var hashIndex = p.url.indexOf('#')
		var hashElem = hashIndex > -1 && document.getElementById(p.url.substr(hashIndex + 1))
		var offset = 0
		if (p.url != location.href && hashElem) {
			for (; hashElem.offsetParent; hashElem = hashElem.offsetParent) {
				offset += hashElem.offsetTop
			}
		}
		scrollTo(0, offset)
		history.pushState(null, null, p.url)
		currentLocationWithoutHash = removeHash(location.href)
		instantanize()
	}

	function mouseout() {
		if (!p.isPreloading || (p.isPreloading && p.isWaitingForCompletion)) {
			return
		}
		p.xhr.abort()
		p.isPreloading = false
		p.isWaitingForCompletion = false
	}

	function init(arg_useBlacklist) {
		if (!supported) {
			triggerPageEvent('change')
			return
		}
		if (currentLocationWithoutHash) { // Already initialized
			return
		}
		useBlacklist = !!arg_useBlacklist
		currentLocationWithoutHash = removeHash(location.href)
		pHistory[currentLocationWithoutHash] = {
			body: document.body.innerHTML,
			title: document.title,
			scrollY: scrollY
		}
		p.xhr = new XMLHttpRequest()
		p.xhr.addEventListener('readystatechange', readystatechange)
		p.url = false
		p.body = false
		p.hasBody = true
		p.title = false
		p.isPreloading = false
		p.isWaitingForCompletion = false
		p.timingStart = false
		p.timing = false
		instantanize(true)

		addEventListener('popstate', function() {
			var loc = removeHash(location.href)
			if (loc == currentLocationWithoutHash) {
				return
			}
			if (!(loc in pHistory)) {
				location.href = location.href // Reloads the page and makes use of cache for assets, unlike location.reload()
				return
			}
			pHistory[currentLocationWithoutHash].scrollY = scrollY

			currentLocationWithoutHash = loc
			document.body.innerHTML = pHistory[loc].body
			scrollTo(0, pHistory[loc].scrollY)
			document.title = pHistory[loc].title
			instantanize()
		})
	}

	return {
		init: init,
		supported: supported,
		on: on,
		debug: debug
	}
}(document, location);
<commit_msg>Get/set body’s outerHTML instead on innerHTML<commit_after>// InstantClick 1.1
// (C) 2014 Alexandre Dieulot
// http://instantclick.io/license.html

var InstantClick = function(document, location) {
	var currentLocationWithoutHash
	var pHistory = {} // short for "preloadHistory"
	var p = {} // short for "preloads"
	var supported = 'pushState' in history
	var useBlacklist
	var listeners = {change: []}

	function removeHash(url) {
		var index = url.indexOf('#')
		if (index == -1) {
			return url
		}
		return url.substr(0, index)
	}

	function getLinkTarget(target) {
		while (target.nodeName != 'A') {
			target = target.parentNode
		}
		return target
	}

	function on(type, listener) {
		listeners[type].push(listener)
	}

	function triggerPageEvent(type) {
		for (var i = 0; i < listeners[type].length; i++) {
			listeners[type][i]()
		}
	}

	function applyBody(body) {
		var doc = document.implementation.createHTMLDocument('')
		doc.documentElement.innerHTML = body
		document.body = doc.body
	}

	function debug() {
		return {
			currentLocationWithoutHash: currentLocationWithoutHash,
			p: p,
			pHistory: pHistory,
			supported: supported,
			useBlacklist: useBlacklist
		}
	}

	function instantanize(isInitializing) {
		var as = document.getElementsByTagName('a'), a, domain = location.protocol + '//' + location.host
		for (var i = as.length - 1; i >= 0; i--) {
			a = as[i]
			if (a.target || // target="_blank" etc.
				a.href.indexOf(domain + '/') != 0 || // another domain (or no href attribute)
				a.href.indexOf('#') > -1 && removeHash(a.href) == currentLocationWithoutHash || // link to an anchor
				(useBlacklist ? a.hasAttribute('data-no-instant') : !a.hasAttribute('data-instant'))) {
				continue
			}
			a.addEventListener('mouseover', queue)
			a.addEventListener('click', click)
		}
		if (!isInitializing) {
			var scripts = document.getElementsByTagName('script'), script, copy, parentNode, nextSibling
			for (i = 0, j = scripts.length; i < j; i++) {
				script = scripts[i]
				if (script.hasAttribute('data-no-instant')) {
					continue
				}
				copy = document.createElement('script')
				if (script.src) {
					copy.src = script.src
				}
				if (script.innerHTML) {
					copy.innerHTML = script.innerHTML
				}
				parentNode = script.parentNode
				nextSibling = script.nextSibling
				parentNode.removeChild(script)
				parentNode.insertBefore(copy, nextSibling)
			}
		}
		triggerPageEvent('change')
	}

	function queue(e) {
		var a = getLinkTarget(e.target)
		a.addEventListener('mouseout', mouseout)
		preload(a.href)
	}

	function preload(url) {
		if ((p.isPreloading && url == p.url) || (p.isPreloading && p.isWaitingForCompletion)) {
			return
		}
		p.isPreloading = true
		p.isWaitingForCompletion = false
		p.url = url
		p.body = false
		p.hasBody = true
		p.timingStart = +new Date
		p.timing = false
		p.xhr.open('GET', url)
		p.xhr.send()
	}

	function readystatechange(e) {
		if (p.xhr.readyState < 4) {
			return
		}

		var text = p.xhr.responseText

		p.timing = +new Date - p.timingStart
		// Note: For debugging (`InstantClick.debug`), we know the page
		// has been preloaded if `p.timing` isn't false.

		var titleIndex = text.indexOf('<title')
		if (titleIndex > -1) {
			p.title = text.substr(text.indexOf('>', titleIndex) + 1)
			p.title = p.title.substr(0, p.title.indexOf('</title'))
		}

		var bodyIndex = text.indexOf('<body')
		if (bodyIndex > -1) {
			p.body = text.substr(bodyIndex)
			var closingIndex = p.body.indexOf('</body')
			if (closingIndex > -1) {
				p.body = p.body.substr(0, closingIndex)
			}

			var urlWithoutHash = removeHash(p.url)
			pHistory[urlWithoutHash] = {
				body: p.body,
				title: p.title,
				scrollY: urlWithoutHash in pHistory ? pHistory[urlWithoutHash].scrollY : 0
			}
		}
		else {
			p.hasBody = false
		}

		if (p.isWaitingForCompletion) {
			display(p.url)
		}
	}

	function click(e) {
		if (e.which > 1 || e.metaKey || e.ctrlKey) { // Opening in new tab
			return
		}
		e.preventDefault()
		display(getLinkTarget(e.target).href)
	}

	function display(url) {
		if (!p.isPreloading || (p.isPreloading && p.isWaitingForCompletion)) {
			/* If the page isn't preloaded, it means
			   the user has focused on a link (with his Tab
			   key) and then pressed Return, which triggered a click.
			   Because very few people do this, it isn't worth handling this
			   case and preloading on focus (also, focussing on a link
			   doesn't mean it's likely that you'll "click" on it), so we just
			   redirect them when they "click".

			   If the page is waiting for completion, the user clicked twice
			   while the page was preloading.
			   Two possibilities:
			   1) He clicks on the same link again, either because it's slow
			      to load (there's no browser loading indicator with
			      InstantClick, so he might think his click hasn't registered
			      if the page isn't loading fast enough) or because he has
			      a habit of double clicking on the web;
			   2) He clicks on another link.

			   In the first case, we redirect him (send him to the page the old
			   way) so that he can have the browser's loading indicator back.
			   In the second case, we redirect him because we haven't preloaded
			   that link, since we were already preloading the last one.

			   Determining if it's a double click might be overkill as there is
			   (hopefully) not that many people that double click on the web.
			   Fighting against the perception that the page is stuck is
			   interesting though, a seemingly good way to do that would be to
			   later incorporate a progress bar.
			*/

			location.href = url
			return
		}
		if (!p.hasBody) {
			location.href = p.url
			return
		}
		if (!p.body) {
			p.isWaitingForCompletion = true
			return
		}
		pHistory[currentLocationWithoutHash].scrollY = scrollY
		p.isPreloading = false
		p.isWaitingForCompletion = false
		applyBody(p.body)
		document.title = p.title
		var hashIndex = p.url.indexOf('#')
		var hashElem = hashIndex > -1 && document.getElementById(p.url.substr(hashIndex + 1))
		var offset = 0
		if (p.url != location.href && hashElem) {
			for (; hashElem.offsetParent; hashElem = hashElem.offsetParent) {
				offset += hashElem.offsetTop
			}
		}
		scrollTo(0, offset)
		history.pushState(null, null, p.url)
		currentLocationWithoutHash = removeHash(location.href)
		instantanize()
	}

	function mouseout() {
		if (!p.isPreloading || (p.isPreloading && p.isWaitingForCompletion)) {
			return
		}
		p.xhr.abort()
		p.isPreloading = false
		p.isWaitingForCompletion = false
	}

	function init(arg_useBlacklist) {
		if (!supported) {
			triggerPageEvent('change')
			return
		}
		if (currentLocationWithoutHash) { // Already initialized
			return
		}
		useBlacklist = !!arg_useBlacklist
		currentLocationWithoutHash = removeHash(location.href)
		pHistory[currentLocationWithoutHash] = {
			body: document.body.outerHTML,
			title: document.title,
			scrollY: scrollY
		}
		p.xhr = new XMLHttpRequest()
		p.xhr.addEventListener('readystatechange', readystatechange)
		p.url = false
		p.body = false
		p.hasBody = true
		p.title = false
		p.isPreloading = false
		p.isWaitingForCompletion = false
		p.timingStart = false
		p.timing = false
		instantanize(true)

		addEventListener('popstate', function() {
			var loc = removeHash(location.href)
			if (loc == currentLocationWithoutHash) {
				return
			}
			if (!(loc in pHistory)) {
				location.href = location.href // Reloads the page and makes use of cache for assets, unlike location.reload()
				return
			}
			pHistory[currentLocationWithoutHash].scrollY = scrollY

			currentLocationWithoutHash = loc
			applyBody(pHistory[loc].body)
			scrollTo(0, pHistory[loc].scrollY)
			document.title = pHistory[loc].title
			instantanize()
		})
	}

	return {
		init: init,
		supported: supported,
		on: on,
		debug: debug
	}
}(document, location);
<|endoftext|>


<commit_before>Meteor.publish('bets', function(){
  return Bets.find();
});

Meteor.publish('betNotifications', function(){
  return BetNotifications.find();
});

Meteor.publish('messages', function(){
  return Messages.find();
});
<commit_msg>Publish usernames.<commit_after>Meteor.publish('bets', function(){
  return Bets.find();
});

Meteor.publish('betNotifications', function(){
  return BetNotifications.find();
});

Meteor.publish('messages', function(){
  return Messages.find();
});

Meteor.publish('allUsernames', function(username){
  return Meteor.users.find();
});
<|endoftext|>


<commit_before>Checklist.KingdomListView = Ember.View.extend({
  templateName: 'kingdom_list_view',
  content: null,
  taxonConceptsController: null,
  filtersController: null,

  isInvisible: true,

  showAnimalia: function(){
    return this.content.get('animaliaPresent');
  }.property(),
  showPlantae: function(){
    return this.content.get('plantaePresent');
  }.property(),
  currentPage: function() {
    return Checklist.get('router').get('filtersController').get('page') + 1;
  }.property(),
  showNext: function(){
    return Checklist.get('router').get('filtersController').get('page') <
      Math.floor(this.content.get('total_cnt') / Checklist.get('router').get('filtersController').get('per_page'));
  }.property(),
  showPrev: function(){
    return Checklist.get('router').get('filtersController').get('page') > 0;
  }.property(),
  nextPage: function(){
    var currentPage = Checklist.get('router').get('filtersController').get('page');
    if (this.get('showNext')){
      Checklist.get('router').get('filtersController').set('page', currentPage + 1);
      Checklist.get('router').transitionTo(
        'search',
        {
          params: $.param(
            Checklist.get('router').get('filtersController').toParams()
          )
        }
      );
    }
  },
  prevPage: function(){
    var currentPage = Checklist.get('router').get('filtersController').get('page');
    if (this.get('showPrev')){
      Checklist.get('router').get('filtersController').set('page', currentPage - 1);
      Checklist.get('router').transitionTo(
        'search',
        {
          params: $.param(
            Checklist.get('router').get('filtersController').toParams()
          )
        }
      );
    }
  },

  didInsertElement: function() {
    $('#loading').fadeOut();
    this.set('isInvisible', false);

    // Initialise history tooltips
    $('a.tooltip').hoverTooltip({
      positionTypeX: 'left',
      positionTypeY: 'top',
      attribute:'title',
      extraOffsetX: -2,
      extraOffsetY: 2,
      tooltipStructure: '

'
    });

    $('a.more-countries-tooltip').hoverTooltip({
      positionTypeX: 'center',
      positionTypeY: 'bottom',
      attribute:'title',
      extraOffsetX: 15,
      extraOffsetY: 40,
      tooltipStructure: '

'
    });

    // Vertical height management for listing rows
    $('.column-container').sameHeight({
      elements: '.column-area',
      flexible: true
    });

    this.createFloatingElements();
    $(window)
     .scroll(this.updateFloatingElements)
     .trigger("scroll")
     .resize(this.onWindowResize);
  },

  onWindowResize: function() {
    $('.floatingHeader').width($('.persist-header').first().width());
  },
  createFloatingElements: function() {
    var clonedHeaderRow;

    /*
     * Clone each defined header and hide it. This will be used
     * as the top-fixed floating header when scrolling.
     */
    $(".persist-area").each(function() {
      clonedHeaderRow = $(this);
      clonedHeaderRow
        .before(clonedHeaderRow.clone())
        .css("width", clonedHeaderRow.width())
        .addClass("floatingHeader")
        .removeClass('persist-area')
        .removeClass('persist-header');
    });

    /*
     * A glorious hack. Calculates groups of species by determining
     * the list items between each header, and using this information
     * to wrap them in a
 to allow grouping necessary for sticky
     * headers.
     *
     * This will be fixed soon, but for now given items are limited to
     * 50 per page, the performance hit is minimal.
     */
    var current_group = [];
    $(".listing-item").each(function(index, item) {
      // For each iteration, if the current item is a header or the
      // last item then we can assume the previous items in
      // current_group are a headed group of species and can be
      // wrapper in the grouping

      if ($(item).hasClass('persist-area') || index == ($('.listing-item').length - 1)) {
        if (current_group.length > 0) {
          var to_wrap = $(current_group).map (function () {return this.toArray();} );
          to_wrap.wrapAll('
');
        }

        current_group = [];
        $(item).removeClass('persist-area');
      }

      current_group.push($(item));
    });
  },
  updateFloatingElements: function() {
    /*
     * Hide and show the cloned headers as appropriate.
     *
     * When we scroll past a higher taxa heading, we make the cloned
     * floating header visible and stick it to the top of the listing
     * secion.
     */
    $(".persist-area").each(function(index, element) {
      var el         = $(this),
      offset         = el.offset(),
      scrollTop      = $(window).scrollTop(),
      floatingHeader = $($(".floatingHeader")[index]);

      if ((scrollTop + 214 > offset.top) && (scrollTop < offset.top + el.height())) {
        floatingHeader.css({
          "visibility": "visible"
        });
      } else {
        floatingHeader.css({
          "visibility": "hidden"
        });
      }
    });

    /* Prevent the paging controls from floating over the footer */

    // Calculate how much of the document remains, and use it
    // to determine how much of the footer is visible
    var remaining = ($(document).height() - $(window).scrollTop())-$(window).height();
    var offset    = ($("#footer").outerHeight() - remaining);
    //
    // Constant space beneath paging
    var bottom_offset = 20;

    $(".paging").css({
      "bottom": (offset > 0 ? offset + bottom_offset : bottom_offset) + "px"
    });
  }
});
<commit_msg>I...I'm not sure how this ever even worked before<commit_after>Checklist.KingdomListView = Ember.View.extend({
  templateName: 'kingdom_list_view',
  content: null,
  taxonConceptsController: null,
  filtersController: null,

  isVisible: false,

  showAnimalia: function(){
    return this.content.get('animaliaPresent');
  }.property(),
  showPlantae: function(){
    return this.content.get('plantaePresent');
  }.property(),
  currentPage: function() {
    return Checklist.get('router').get('filtersController').get('page') + 1;
  }.property(),
  showNext: function(){
    return Checklist.get('router').get('filtersController').get('page') <
      Math.floor(this.content.get('total_cnt') / Checklist.get('router').get('filtersController').get('per_page'));
  }.property(),
  showPrev: function(){
    return Checklist.get('router').get('filtersController').get('page') > 0;
  }.property(),
  nextPage: function(){
    var currentPage = Checklist.get('router').get('filtersController').get('page');
    if (this.get('showNext')){
      Checklist.get('router').get('filtersController').set('page', currentPage + 1);
      Checklist.get('router').transitionTo(
        'search',
        {
          params: $.param(
            Checklist.get('router').get('filtersController').toParams()
          )
        }
      );
    }
  },
  prevPage: function(){
    var currentPage = Checklist.get('router').get('filtersController').get('page');
    if (this.get('showPrev')){
      Checklist.get('router').get('filtersController').set('page', currentPage - 1);
      Checklist.get('router').transitionTo(
        'search',
        {
          params: $.param(
            Checklist.get('router').get('filtersController').toParams()
          )
        }
      );
    }
  },

  didInsertElement: function() {
    $('#loading').fadeOut();
    this.set('isVisible', true);

    // Initialise history tooltips
    $('a.tooltip').hoverTooltip({
      positionTypeX: 'left',
      positionTypeY: 'top',
      attribute:'title',
      extraOffsetX: -2,
      extraOffsetY: 2,
      tooltipStructure: '

'
    });

    $('a.more-countries-tooltip').hoverTooltip({
      positionTypeX: 'center',
      positionTypeY: 'bottom',
      attribute:'title',
      extraOffsetX: 15,
      extraOffsetY: 40,
      tooltipStructure: '

'
    });

    // Vertical height management for listing rows
    $('.column-container').sameHeight({
      elements: '.column-area',
      flexible: true
    });

    this.createFloatingElements();
    $(window)
     .scroll(this.updateFloatingElements)
     .trigger("scroll")
     .resize(this.onWindowResize);
  },

  onWindowResize: function() {
    $('.floatingHeader').width($('.persist-header').first().width());
  },
  createFloatingElements: function() {
    var clonedHeaderRow;

    /*
     * Clone each defined header and hide it. This will be used
     * as the top-fixed floating header when scrolling.
     */
    $(".persist-area").each(function() {
      clonedHeaderRow = $(this);
      clonedHeaderRow
        .before(clonedHeaderRow.clone())
        .css("width", clonedHeaderRow.width())
        .addClass("floatingHeader")
        .removeClass('persist-area')
        .removeClass('persist-header');
    });

    /*
     * A glorious hack. Calculates groups of species by determining
     * the list items between each header, and using this information
     * to wrap them in a
 to allow grouping necessary for sticky
     * headers.
     *
     * This will be fixed soon, but for now given items are limited to
     * 50 per page, the performance hit is minimal.
     */
    var current_group = [];
    $(".listing-item").each(function(index, item) {
      // For each iteration, if the current item is a header or the
      // last item then we can assume the previous items in
      // current_group are a headed group of species and can be
      // wrapper in the grouping

      if ($(item).hasClass('persist-area') || index == ($('.listing-item').length - 1)) {
        if (current_group.length > 0) {
          var to_wrap = $(current_group).map (function () {return this.toArray();} );
          to_wrap.wrapAll('
');
        }

        current_group = [];
        $(item).removeClass('persist-area');
      }

      current_group.push($(item));
    });
  },
  updateFloatingElements: function() {
    /*
     * Hide and show the cloned headers as appropriate.
     *
     * When we scroll past a higher taxa heading, we make the cloned
     * floating header visible and stick it to the top of the listing
     * secion.
     */
    $(".persist-area").each(function(index, element) {
      var el         = $(this),
      offset         = el.offset(),
      scrollTop      = $(window).scrollTop(),
      floatingHeader = $($(".floatingHeader")[index]);

      if ((scrollTop + 214 > offset.top) && (scrollTop < offset.top + el.height())) {
        floatingHeader.css({
          "visibility": "visible"
        });
      } else {
        floatingHeader.css({
          "visibility": "hidden"
        });
      }
    });

    /* Prevent the paging controls from floating over the footer */

    // Calculate how much of the document remains, and use it
    // to determine how much of the footer is visible
    var remaining = ($(document).height() - $(window).scrollTop())-$(window).height();
    var offset    = ($("#footer").outerHeight() - remaining);
    //
    // Constant space beneath paging
    var bottom_offset = 20;

    $(".paging").css({
      "bottom": (offset > 0 ? offset + bottom_offset : bottom_offset) + "px"
    });
  }
});
<|endoftext|>


<commit_before>function demoSetup(apis) {

  var apiOptions = $('#demo-api');
  apiOptions.empty();
  $.each(apis, function() {
    if(this.enabled) {
      apiOptions.append($("<option />").val(this.id).text(this.id));
    }
  });

  $('#demo-results').load(demoResultsChange);

  $('#demo').show();
}

function demoTeardown() {
  $('#demo-results').empty();
  $('#demo').hide();
}

function doDemo() {
  var fullUrl = '';
  var demoMethod = $('#demo-method').val();
  var demoRoute = $('#demo-route').val();
  var demoApi = $('#demo-api').val();
  var demoUrl = $('#demo-url').val().trim();

  if(demoUrl.length===0) {
    demoUrl = '/';
  }
  else if(demoUrl.charAt(0) !== '/') {
    demoUrl = '/' + demoUrl;
  }

  switch(demoRoute) {
    case '/api':
    case '/data':
      break;
    default:
      console.log(demoRoute + ' route not supported');
      return; // not supported
  }

  if(demoMethod) {
    demoMethod = demoMethod.toUpperCase();
  }

  switch(demoMethod) {
    case 'GET':
      if(demoRoute === '/data') {
        fullUrl = demoRoute + demoUrl;
      }
      else {
        fullUrl = demoRoute + '/' + demoApi + demoUrl;
      }
      break;
    case 'POST':
      if(demoRoute !== '/data') {
        console.log(demoMethod + ' method not supported for ' + demoRoute);
        return; // not supported
      }
      fullUrl = demoRoute + demoUrl;
      break;
    default:
      console.log(demoMethod + ' method not supported');
      return; // not supported
  }

  console.log(demoMethod + ' submitted for ' + fullUrl);
  $('#demo-results').empty();

  if(demoMethod === 'GET') {
    $('#demo-results').attr('src',fullUrl);
  }
  else {
    var demoForm = document.createElement('form');
    demoForm.method = demoMethod;
    demoForm.action = fullUrl;
    demoForm.target = 'demo-results';
    demoForm.submit();
  }

  $('#demo-results').show();
}

function demoRouteChange() {
  var demoRoute = $('#demo-route').val();

  $('#demo-method').empty();

  if(demoRoute === '/data') {
    $('#demo-method').append($("<option />").val('GET').text('GET'));
    $('#demo-method').append($("<option />").val('POST').text('POST'));

    $('#demo-api').hide();
    $('#demo-method').show();
    $('#demo-url').show();
    $('#demo-submit').show();
  }
  else if(demoRoute === '/api') {
    $('#demo-method').append($("<option />").val('GET').text('GET'));

    $('#demo-api').show();
    $('#demo-method').show();
    $('#demo-url').show();
    $('#demo-submit').show();
  }
  else {
    $('#demo-api').hide();
    $('#demo-method').hide();
    $('#demo-url').hide();
    $('#demo-submit').hide();
  }

  $('#demo-results').hide();
}

function demoMethodChange() {
  var demoRoute = $('#demo-route').val();
  var demoMethod = $('#demo-method').val();

  if(demoRoute == '/data' && demoMethod === 'GET') {
    $('#demo-api').hide();
  }
  else {
    $('#demo-api').show();
  }
}

function demoResultsChange() {
  // if json content, make it pretty
  try {
    var demoResults = $('#demo-results').contents().find('pre').html();
    if(demoResults) {
      demoResults = JSON.stringify(JSON.parse(demoResults), undefined, 2);
      $('#demo-results').contents().find('pre').html(demoResults);
    }
  }
  catch(e) {
    //console.log('pretty json error:', e);
  }
}
<commit_msg>ui changes<commit_after>function demoSetup(apis) {

  var apiOptions = $('#demo-api');
  apiOptions.empty();
  $.each(apis, function() {
    if(this.enabled) {
      apiOptions.append($("<option />").val(this.id).text(this.id));
    }
  });

  $('#demo-results').load(demoResultsChange);

  $('#demo').show();
}

function demoTeardown() {
  $('#demo-results').empty();
  $('#demo').hide();
}

function doDemo() {
  var fullUrl = '';
  var demoMethod = $('#demo-method').val();
  var demoRoute = $('#demo-route').val();
  var demoApi = $('#demo-api').val();
  var demoUrl = $('#demo-url').val().trim();

  if(demoUrl.length===0) {
    demoUrl = '/';
  }
  else if(demoUrl.charAt(0) !== '/') {
    demoUrl = '/' + demoUrl;
  }

  switch(demoRoute) {
    case '/api':
    case '/data':
      break;
    default:
      console.log(demoRoute + ' route not supported');
      return; // not supported
  }

  if(demoMethod) {
    demoMethod = demoMethod.toUpperCase();
  }

  switch(demoMethod) {
    case 'GET':
      if(demoRoute === '/data') {
        fullUrl = demoRoute + demoUrl;
      }
      else {
        fullUrl = demoRoute + '/' + demoApi + demoUrl;
      }
      break;
    case 'POST':
      if(demoRoute !== '/data') {
        console.log(demoMethod + ' method not supported for ' + demoRoute);
        return; // not supported
      }
      fullUrl = demoRoute + '/' + demoApi + demoUrl;
      break;
    default:
      console.log(demoMethod + ' method not supported');
      return; // not supported
  }

  console.log(demoMethod + ' submitted for ' + fullUrl);
  $('#demo-results').empty();

  if(demoMethod === 'GET') {
    $('#demo-results').attr('src',fullUrl);
  }
  else {
    var demoForm = document.createElement('form');
    demoForm.method = demoMethod;
    demoForm.action = fullUrl;
    demoForm.target = 'demo-results';
    demoForm.submit();
  }

  $('#demo-results').show();
}

function demoRouteChange() {
  var demoRoute = $('#demo-route').val();

  $('#demo-method').empty();

  if(demoRoute === '/data') {
    $('#demo-method').append($("<option />").val('GET').text('GET'));
    $('#demo-method').append($("<option />").val('POST').text('POST'));

    $('#demo-api').hide();
    $('#demo-method').show();
    $('#demo-url').show();
    $('#demo-submit').show();
  }
  else if(demoRoute === '/api') {
    $('#demo-method').append($("<option />").val('GET').text('GET'));

    $('#demo-api').show();
    $('#demo-method').show();
    $('#demo-url').show();
    $('#demo-submit').show();
  }
  else {
    $('#demo-api').hide();
    $('#demo-method').hide();
    $('#demo-url').hide();
    $('#demo-submit').hide();
  }

  $('#demo-results').hide();
}

function demoMethodChange() {
  var demoRoute = $('#demo-route').val();
  var demoMethod = $('#demo-method').val();

  if(demoRoute == '/data' && demoMethod === 'GET') {
    $('#demo-api').hide();
  }
  else {
    $('#demo-api').show();
  }
}

function demoResultsChange() {
  // if json content, make it pretty
  try {
    var demoResults = $('#demo-results').contents().find('pre').html();
    if(demoResults) {
      demoResults = JSON.stringify(JSON.parse(demoResults), undefined, 2);
      $('#demo-results').contents().find('pre').html(demoResults);
    }
  }
  catch(e) {
    //console.log('pretty json error:', e);
  }
}
<|endoftext|>


<commit_before>// validations/email.js
import {
  validatePresence,
  validateLength,
  validateConfirmation,
} from 'ember-changeset-validations/validators';

export default {
  email: [
    validatePresence(true),
    validateLength({ min: 8 }),
  ],
  emailConfirmation: validateConfirmation({ on: 'email' })
};
<commit_msg>JS: updated email validation, tested email, email reset working<commit_after>// validations/email.js
import {
  validatePresence,
  validateFormat,
  validateLength,
  validateConfirmation,
} from 'ember-changeset-validations/validators';

export default {
  email: [
    validatePresence(true),
    validateFormat({type: 'email'}),
    validateLength({ min: 8 })
  ],
  emailConfirmation: validateConfirmation({ on: 'email' })
};
<|endoftext|>


<commit_before>var _ = require('underscore');
var oled = null;
var currentProgram = null;
var backupProgram = null;
var currentName = "";
var stack = [];
var screenSaverHandle = null;

exports.busy = false;

function activity() {
    oled.activity();
}

exports.init = function(menuController) {
    oled = menuController;
}

function load(program, selected) {
    if (program.alternate && typeof program.alternate == "function") {
        var alternate = program.alternate();
        if (alternate !== false) {
            load(alternate, selected);
            return;
        }
    }

    currentName = program.name;
    currentProgram = _.clone(program);

    if (currentProgram.items && currentProgram.items.slice) {
        currentProgram.items = currentProgram.items.slice(0);
        currentProgram.items = currentProgram.items.filter(function(item) {
            if (typeof item.condition === "function") {
                return item.condition();
            } else {
                return true;
            }
        });
        for (var i = 0; i < currentProgram.items.length; i++) {
            var item = currentProgram.items[i];
            if (typeof item.name == 'function') {
                currentProgram.items[i] = _.clone(item);
                item = currentProgram.items[i];
                item.name = item.name();
            }
            if (selected == null) {
                if (item.selected && typeof item.selected === "function") {
                    if (item.selected()) {
                        selected = i;
                        break;
                    }
                } else if (item.action && item.action.selected && typeof item.action.selected === "function") {
                    if (item.action.selected()) {
                        selected = i;
                        break;
                    }
                }
            }
        }
        if(selected >= currentProgram.items.length) selected = currentProgram.items.length - 1;
    }
    if (currentProgram.type == "timelapse") {
        oled.setTimelapseMode(true);
    } else {
        oled.setTimelapseMode(false);
    }
    if (currentProgram.type == "menu" && currentProgram.hasImages == true) {
        oled.createMenuImage(currentProgram.items.map(function(item) {
            return {
                name: item.name,
                line2: item.line2,
                image: item.image
            };
        }), selected || 0);
        oled.update();
    } else if (currentProgram.type == "menu") {
        oled.create(currentProgram.items.map(function(item) {
            return item.name;
        }), selected || 0);
        oled.update();
    }
    if (currentProgram.type == "options") {
        oled.value(currentProgram.items, selected || 0);
        oled.update();
    }
    if (currentProgram.type == "textInput") {
        oled.text(currentProgram.name, currentProgram.value);
        oled.update();
    }
    if (currentProgram.type == "textDisplay") {
        oled.displayText(currentProgram.name, currentProgram.value);
        oled.update();
    }
    if (currentProgram.type == "png" && currentProgram.file) {
        oled.png(currentProgram.file);
    }
    if (currentProgram.type == "function" && currentProgram.fn) {
        currentProgram.fn(currentProgram.arg, function(err, program) {
            if(!err && program && (program.type)) {
                load(program);
            } else {
                console.log("function completed, going back");
                setTimeout(back);
            }
        });
    }
    if (currentProgram.type == "menuFunction" && currentProgram.fn) {
        currentProgram.fn(currentProgram.arg, function(err, p) {
            if (!err) exports.load(p, true);
        });
    }
}

exports.load = function(menuProgram, noPush, selected, forceStack) {
    exports.busy = false;
    if ((forceStack && backupProgram != null) || (backupProgram != null && !noPush && backupProgram.type != "options" && backupProgram.type != "function")) {
        stack.push({
            program: backupProgram,
            selected: oled.selected,
            name: currentName
        });
    }
    backupProgram = menuProgram;

    if (typeof menuProgram == 'function') {
        exports.busy = true;
        oled.showBusy();
        menuProgram(function(arg, program) {
            exports.busy = false;
            load(program, selected);
        });
    } else {
        load(menuProgram, selected);
    }

}

exports.reload = function() {
    if (backupProgram.type == "menu" || backupProgram.type == "options") {
        exports.load(backupProgram, true, oled.selected);
    }
}

exports.up = function(alt) {
    activity();
    if(exports.busy) return;
    if (currentProgram.type == "menu" || currentProgram.type == "options") {
        oled.up();
    } else if(currentProgram.type == "textDisplay") {
        oled.up();
    } else if(currentProgram.type == "textInput") {
        if(alt) {
            oled.textMoveBackward();
        } else {
            oled.up();
        }
    }
}
exports.down = function(alt) {
    activity();
    if(exports.busy) return;
    if (currentProgram.type == "menu" || currentProgram.type == "options") {
        oled.down();
    } else if(currentProgram.type == "textDisplay") {
        oled.down();
    } else if(currentProgram.type == "textInput") {
        if(alt) {
            oled.textMoveForward();
        } else {
            oled.down();
        }
    }
}
exports.enter = function(alt) {
    activity();
    if(exports.busy) return;
    if (currentProgram.type == "menu" || currentProgram.type == "options") {
        if(currentProgram.items[oled.selected]) exports.load(currentProgram.items[oled.selected].action);
    } else if (currentProgram.type == "textInput") {
        if(alt) {
            oled.textMoveForward();
        } else {
            //console.log("resulting string", oled.getTextValue());
            if(currentProgram.onSave) currentProgram.onSave(oled.getTextValue());
            back();
        }
    } else if (currentProgram.type == "png") {
        back();
    } else if (currentProgram.enter && typeof currentProgram.enter == "function") {
        currentProgram.enter();
    }
}
exports.help = function() {
    activity();
    if(exports.busy) return;
    if(currentProgram.type == "textDisplay" && currentProgram.origin == "help") {
        back();
    } else if (currentProgram.type == "menu" || currentProgram.type == "options") {
        if (currentProgram.items[oled.selected] && currentProgram.items[oled.selected].help) {
            exports.load({
                type: "textDisplay",
                origin: "help",
                name: "HELP - " + currentProgram.items[oled.selected].name || currentProgram.name,
                value: currentProgram.items[oled.selected].help
            });
        }
    } else if(currentProgram.help) {
        exports.load({
            type: "textDisplay",
            origin: "help",
            name: "HELP - " + currentProgram.name,
            value: currentProgram.help
        });
    }
}
exports.alert = function(title, text) {
    activity();
    exports.load({
        type: "textDisplay",
        origin: "alert",
        name: title,
        value: text
    });
}
exports.currentOrigin = function() {
    return currentProgram.origin;
}
exports.dismissAlert = function() {
    activity();
    if (currentProgram.type == "textDisplay" && currentProgram.origin == "alert" ) back();
}
exports.button3 = function() {
    activity();
    if(exports.busy) return;
    if (currentProgram.type == "menu" && currentProgram.items[oled.selected] && currentProgram.items[oled.selected].button3) {
        currentProgram.items[oled.selected].button3(currentProgram.items[oled.selected]);
    } else if (currentProgram.type == "textInput") {
        oled.textCycleMode();
    } else if (currentProgram.button3 && typeof currentProgram.button3 == "function") {
        currentProgram.button3();
    }
}
function back() {
    if(stack.length == 0) {
        console.log("already at menu top");
        return;
    }
    var b;
    do {
        b = stack.pop();
    } while((!b || !b.name) && stack.length > 0);
    if(currentProgram.origin == "prompt" && stack.length > 0) {
        do {
            b = stack.pop();
        } while((!b || !b.name) && stack.length > 0);
    }
    console.log("BACK to " + b.name);
    exports.load(b.program, true, b.selected);
}
exports.back = function() {
    exports.busy = false;
    if (stack.length > 0) {
        activity();
        back();
    } else {
        //if (oled.visible) oled.hide();
    }
}

exports.backButton = function() {
    if (stack.length > 0) {
        activity();
        if(exports.busy) return;
        back();
    } else {
        if (oled.visible) oled.hide();
    }
}

exports.set = function(object, key, value, callback) {
    return {
        type: "function",
        fn: function(arg, cb) {
            object[key] = value;
            if(callback) {
                callback(cb);
            } else {
                cb && cb();
            }
        },
        selected: exports.select(object, key, value)
    }
}

exports.select = function(object, key, value) {
    return function() {
        return object && object[key] == value;
    }
}

exports.confirmationPrompt = function(promptText, optionText1, optionText2, helpText, callback1, callback2) {
    exports.load({
        name: promptText,
        origin: "prompt",
        type: "options",
        items: [{
            name: promptText,
            value: optionText1,
            help: helpText,
            action: {
                type: 'function',
                fn: function(arg, cb) {
                    if(callback1) {
                        callback1(cb);
                    } else {
                        back();
                        cb();
                    }
                }
            }
        }, {
            name: promptText,
            value: optionText2,
            help: helpText,
            action: {
                type: 'function',
                fn: function(arg, cb) {
                    if(callback2) {
                        callback2(cb);
                    } else {
                        back();
                        cb();
                    }
                }
            }
        }]
    }, null, null, true);
}

exports.defaultStatusString = "";
var statusTimeoutHandle = null;

exports.status = function(status) {
    if(statusTimeoutHandle) clearTimeout(statusTimeoutHandle);
    if(status) {
        oled.writeStatus(status);
        if(exports.busy) oled.showBusy();
        if(exports.defaultStatusString) {
            statusTimeoutHandle = setTimeout(function(){
                oled.writeStatus(exports.defaultStatusString);
                if(exports.busy) oled.showBusy();
            }, 6000);
        }
    } else {
        oled.writeStatus(exports.defaultStatusString);
        if(exports.busy) oled.showBusy();
    }
}

exports.defaultStatus = function(status) {
    exports.defaultStatusString = status;
}
<commit_msg>debugging<commit_after>var _ = require('underscore');
var oled = null;
var currentProgram = null;
var backupProgram = null;
var currentName = "";
var stack = [];
var screenSaverHandle = null;

exports.busy = false;

function activity() {
    oled.activity();
}

exports.init = function(menuController) {
    oled = menuController;
}

function load(program, selected) {
    if(!program) return exports.back();
    if (program.alternate && typeof program.alternate == "function") {
        var alternate = program.alternate();
        if (alternate !== false) {
            load(alternate, selected);
            return;
        }
    }

    currentName = program.name;
    currentProgram = _.clone(program);

    if (currentProgram.items && currentProgram.items.slice) {
        currentProgram.items = currentProgram.items.slice(0);
        currentProgram.items = currentProgram.items.filter(function(item) {
            if (typeof item.condition === "function") {
                return item.condition();
            } else {
                return true;
            }
        });
        for (var i = 0; i < currentProgram.items.length; i++) {
            var item = currentProgram.items[i];
            if (typeof item.name == 'function') {
                currentProgram.items[i] = _.clone(item);
                item = currentProgram.items[i];
                item.name = item.name();
            }
            if (selected == null) {
                if (item.selected && typeof item.selected === "function") {
                    if (item.selected()) {
                        selected = i;
                        break;
                    }
                } else if (item.action && item.action.selected && typeof item.action.selected === "function") {
                    if (item.action.selected()) {
                        selected = i;
                        break;
                    }
                }
            }
        }
        if(selected >= currentProgram.items.length) selected = currentProgram.items.length - 1;
    }
    if (currentProgram.type == "timelapse") {
        oled.setTimelapseMode(true);
    } else {
        oled.setTimelapseMode(false);
    }
    if (currentProgram.type == "menu" && currentProgram.hasImages == true) {
        oled.createMenuImage(currentProgram.items.map(function(item) {
            return {
                name: item.name,
                line2: item.line2,
                image: item.image
            };
        }), selected || 0);
        oled.update();
    } else if (currentProgram.type == "menu") {
        oled.create(currentProgram.items.map(function(item) {
            return item.name;
        }), selected || 0);
        oled.update();
    }
    if (currentProgram.type == "options") {
        oled.value(currentProgram.items, selected || 0);
        oled.update();
    }
    if (currentProgram.type == "textInput") {
        oled.text(currentProgram.name, currentProgram.value);
        oled.update();
    }
    if (currentProgram.type == "textDisplay") {
        oled.displayText(currentProgram.name, currentProgram.value);
        oled.update();
    }
    if (currentProgram.type == "png" && currentProgram.file) {
        oled.png(currentProgram.file);
    }
    if (currentProgram.type == "function" && currentProgram.fn) {
        currentProgram.fn(currentProgram.arg, function(err, program) {
            if(!err && program && (program.type)) {
                load(program);
            } else {
                console.log("function completed, going back");
                setTimeout(back);
            }
        });
    }
    if (currentProgram.type == "menuFunction" && currentProgram.fn) {
        currentProgram.fn(currentProgram.arg, function(err, p) {
            if (!err) exports.load(p, true);
        });
    }
}

exports.load = function(menuProgram, noPush, selected, forceStack) {
    exports.busy = false;
    if ((forceStack && backupProgram != null) || (backupProgram != null && !noPush && backupProgram.type != "options" && backupProgram.type != "function")) {
        stack.push({
            program: backupProgram,
            selected: oled.selected,
            name: currentName
        });
    }
    backupProgram = menuProgram;

    if (typeof menuProgram == 'function') {
        exports.busy = true;
        oled.showBusy();
        menuProgram(function(arg, program) {
            exports.busy = false;
            load(program, selected);
        });
    } else {
        load(menuProgram, selected);
    }

}

exports.reload = function() {
    if (backupProgram.type == "menu" || backupProgram.type == "options") {
        exports.load(backupProgram, true, oled.selected);
    }
}

exports.up = function(alt) {
    activity();
    if(exports.busy) return;
    if (currentProgram.type == "menu" || currentProgram.type == "options") {
        oled.up();
    } else if(currentProgram.type == "textDisplay") {
        oled.up();
    } else if(currentProgram.type == "textInput") {
        if(alt) {
            oled.textMoveBackward();
        } else {
            oled.up();
        }
    }
}
exports.down = function(alt) {
    activity();
    if(exports.busy) return;
    if (currentProgram.type == "menu" || currentProgram.type == "options") {
        oled.down();
    } else if(currentProgram.type == "textDisplay") {
        oled.down();
    } else if(currentProgram.type == "textInput") {
        if(alt) {
            oled.textMoveForward();
        } else {
            oled.down();
        }
    }
}
exports.enter = function(alt) {
    activity();
    if(exports.busy) return;
    if (currentProgram.type == "menu" || currentProgram.type == "options") {
        if(currentProgram.items[oled.selected]) exports.load(currentProgram.items[oled.selected].action);
    } else if (currentProgram.type == "textInput") {
        if(alt) {
            oled.textMoveForward();
        } else {
            //console.log("resulting string", oled.getTextValue());
            if(currentProgram.onSave) currentProgram.onSave(oled.getTextValue());
            back();
        }
    } else if (currentProgram.type == "png") {
        back();
    } else if (currentProgram.enter && typeof currentProgram.enter == "function") {
        currentProgram.enter();
    }
}
exports.help = function() {
    activity();
    if(exports.busy) return;
    if(currentProgram.type == "textDisplay" && currentProgram.origin == "help") {
        back();
    } else if (currentProgram.type == "menu" || currentProgram.type == "options") {
        if (currentProgram.items[oled.selected] && currentProgram.items[oled.selected].help) {
            exports.load({
                type: "textDisplay",
                origin: "help",
                name: "HELP - " + currentProgram.items[oled.selected].name || currentProgram.name,
                value: currentProgram.items[oled.selected].help
            });
        }
    } else if(currentProgram.help) {
        exports.load({
            type: "textDisplay",
            origin: "help",
            name: "HELP - " + currentProgram.name,
            value: currentProgram.help
        });
    }
}
exports.alert = function(title, text) {
    activity();
    exports.load({
        type: "textDisplay",
        origin: "alert",
        name: title,
        value: text
    });
}
exports.currentOrigin = function() {
    return currentProgram.origin;
}
exports.dismissAlert = function() {
    activity();
    if (currentProgram.type == "textDisplay" && currentProgram.origin == "alert" ) back();
}
exports.button3 = function() {
    activity();
    if(exports.busy) return;
    if (currentProgram.type == "menu" && currentProgram.items[oled.selected] && currentProgram.items[oled.selected].button3) {
        currentProgram.items[oled.selected].button3(currentProgram.items[oled.selected]);
    } else if (currentProgram.type == "textInput") {
        oled.textCycleMode();
    } else if (currentProgram.button3 && typeof currentProgram.button3 == "function") {
        currentProgram.button3();
    }
}
function back() {
    if(stack.length == 0) {
        console.log("already at menu top");
        return;
    }
    var b;
    do {
        b = stack.pop();
    } while((!b || !b.name) && stack.length > 0);
    if(currentProgram.origin == "prompt" && stack.length > 0) {
        do {
            b = stack.pop();
        } while((!b || !b.name) && stack.length > 0);
    }
    console.log("BACK to " + b.name);
    exports.load(b.program, true, b.selected);
}
exports.back = function() {
    exports.busy = false;
    if (stack.length > 0) {
        activity();
        back();
    } else {
        //if (oled.visible) oled.hide();
    }
}

exports.backButton = function() {
    if (stack.length > 0) {
        activity();
        if(exports.busy) return;
        back();
    } else {
        if (oled.visible) oled.hide();
    }
}

exports.set = function(object, key, value, callback) {
    return {
        type: "function",
        fn: function(arg, cb) {
            object[key] = value;
            if(callback) {
                callback(cb);
            } else {
                cb && cb();
            }
        },
        selected: exports.select(object, key, value)
    }
}

exports.select = function(object, key, value) {
    return function() {
        return object && object[key] == value;
    }
}

exports.confirmationPrompt = function(promptText, optionText1, optionText2, helpText, callback1, callback2) {
    exports.load({
        name: promptText,
        origin: "prompt",
        type: "options",
        items: [{
            name: promptText,
            value: optionText1,
            help: helpText,
            action: {
                type: 'function',
                fn: function(arg, cb) {
                    if(callback1) {
                        callback1(cb);
                    } else {
                        back();
                        cb();
                    }
                }
            }
        }, {
            name: promptText,
            value: optionText2,
            help: helpText,
            action: {
                type: 'function',
                fn: function(arg, cb) {
                    if(callback2) {
                        callback2(cb);
                    } else {
                        back();
                        cb();
                    }
                }
            }
        }]
    }, null, null, true);
}

exports.defaultStatusString = "";
var statusTimeoutHandle = null;

exports.status = function(status) {
    if(statusTimeoutHandle) clearTimeout(statusTimeoutHandle);
    if(status) {
        oled.writeStatus(status);
        if(exports.busy) oled.showBusy();
        if(exports.defaultStatusString) {
            statusTimeoutHandle = setTimeout(function(){
                oled.writeStatus(exports.defaultStatusString);
                if(exports.busy) oled.showBusy();
            }, 6000);
        }
    } else {
        oled.writeStatus(exports.defaultStatusString);
        if(exports.busy) oled.showBusy();
    }
}

exports.defaultStatus = function(status) {
    exports.defaultStatusString = status;
}
<|endoftext|>


<commit_before>Meteor.publishComposite('boards', function() {
    return {
        find: function() {
            return Boards.find({ userId: this.userId });
        }
    }
});

Meteor.publishComposite('board', function(boardId) {
    return {
        find: function() {
            return Boards.find({ _id: boardId });
        },
        children: [
            {
                find: function(board) {
                    return Lists.find({ boardId: board._id, closed: false });
                },
                children: [
                    {
                        find: function(list, board) {
                            return Cards.find({ listId: list._id, closed: false });
                        }
                    }
                ]
            }
        ]
    }
});
<commit_msg>Private, Public boards allows publishComposite #26<commit_after>Meteor.publishComposite('boards', function() {
    return {
        find: function() {
            return Boards.find({ userId: this.userId });
        }
    }
});

Meteor.publishComposite('board', function(boardId) {
    return {
        find: function() {
            var boards = Boards.find({ _id: boardId, userId: this.userId });

            // currentUser Private or Public board
            if (boards.count()) return boards;

            // Public board
            return Boards.find({ _id: boardId, permission: 'public' });
        },
        children: [
            {
                find: function(board) {
                    return Lists.find({ boardId: board._id, closed: false });
                },
                children: [
                    {
                        find: function(list, board) {
                            return Cards.find({ listId: list._id, closed: false });
                        }
                    }
                ]
            }
        ]
    }
});
<|endoftext|>


<commit_before>'use strict'

const {EventEmitter} = require('events')
const {ipcMain, session, Menu, NavigationController} = require('electron')

// session is not used here, the purpose is to make sure session is initalized
// before the webContents module.
session

const binding = process.atomBinding('web_contents')
const debuggerBinding = process.atomBinding('debugger')

let nextId = 0
const getNextId = function () {
  return ++nextId
}

const PDFPageSize = {
  A5: {
    custom_display_name: 'A5',
    height_microns: 210000,
    name: 'ISO_A5',
    width_microns: 148000
  },
  A4: {
    custom_display_name: 'A4',
    height_microns: 297000,
    name: 'ISO_A4',
    is_default: 'true',
    width_microns: 210000
  },
  A3: {
    custom_display_name: 'A3',
    height_microns: 420000,
    name: 'ISO_A3',
    width_microns: 297000
  },
  Legal: {
    custom_display_name: 'Legal',
    height_microns: 355600,
    name: 'NA_LEGAL',
    width_microns: 215900
  },
  Letter: {
    custom_display_name: 'Letter',
    height_microns: 279400,
    name: 'NA_LETTER',
    width_microns: 215900
  },
  Tabloid: {
    height_microns: 431800,
    name: 'NA_LEDGER',
    width_microns: 279400,
    custom_display_name: 'Tabloid'
  }
}

// Following methods are mapped to webFrame.
const webFrameMethods = [
  'insertText',
  'setZoomFactor',
  'setZoomLevel',
  'setZoomLevelLimits'
]

// Add JavaScript wrappers for WebContents class.
const wrapWebContents = function (webContents) {
  // webContents is an EventEmitter.
  Object.setPrototypeOf(webContents, EventEmitter.prototype)

  // Every remote callback from renderer process would add a listenter to the
  // render-view-deleted event, so ignore the listenters warning.
  webContents.setMaxListeners(0)

  // WebContents::send(channel, args..)
  // WebContents::sendToAll(channel, args..)
  const sendWrapper = (allFrames, channel, ...args) => {
    if (channel == null) {
      throw new Error('Missing required channel argument')
    }
    return webContents._send(allFrames, channel, args)
  }
  webContents.send = sendWrapper.bind(null, false)
  webContents.sendToAll = sendWrapper.bind(null, true)

  // The navigation controller.
  const controller = new NavigationController(webContents)
  for (const name in NavigationController.prototype) {
    const method = NavigationController.prototype[name]
    if (method instanceof Function) {
      webContents[name] = function () {
        return method.apply(controller, arguments)
      }
    }
  }

  // Mapping webFrame methods.
  for (const method of webFrameMethods) {
    webContents[method] = function (...args) {
      this.send('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, args)
    }
  }

  const asyncWebFrameMethods = function (requestId, method, callback, ...args) {
    this.send('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args)
    ipcMain.once(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, function (event, result) {
      if (callback) callback(result)
    })
  }

  // Make sure webContents.executeJavaScript would run the code only when the
  // webContents has been loaded.
  webContents.executeJavaScript = function (code, hasUserGesture, callback) {
    const requestId = getNextId()
    if (typeof hasUserGesture === 'function') {
      callback = hasUserGesture
      hasUserGesture = false
    }
    if (this.getURL() && !this.isLoadingMainFrame()) {
      asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)
    } else {
      this.once('did-finish-load', () => {
        asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)
      })
    }
  }

  // Dispatch IPC messages to the ipc module.
  webContents.on('ipc-message', function (event, [channel, ...args]) {
    ipcMain.emit(channel, event, ...args)
  })
  webContents.on('ipc-message-sync', function (event, [channel, ...args]) {
    Object.defineProperty(event, 'returnValue', {
      set: function (value) {
        return event.sendReply(JSON.stringify(value))
      },
      get: function () {}
    })
    ipcMain.emit(channel, event, ...args)
  })

  // Handle context menu action request from pepper plugin.
  webContents.on('pepper-context-menu', function (event, params) {
    const menu = Menu.buildFromTemplate(params.menu)
    menu.popup(params.x, params.y)
  })

  // The devtools requests the webContents to reload.
  webContents.on('devtools-reload-page', function () {
    webContents.reload()
  })

  // Delays the page-title-updated event to next tick.
  webContents.on('-page-title-updated', function (...args) {
    setImmediate(() => {
      this.emit.apply(this, ['page-title-updated'].concat(args))
    })
  })

  webContents.printToPDF = function (options, callback) {
    const printingSetting = {
      pageRage: [],
      mediaSize: {},
      landscape: false,
      color: 2,
      headerFooterEnabled: false,
      marginsType: 0,
      isFirstRequest: false,
      requestID: getNextId(),
      previewModifiable: true,
      printToPDF: true,
      printWithCloudPrint: false,
      printWithPrivet: false,
      printWithExtension: false,
      deviceName: 'Save as PDF',
      generateDraftData: true,
      fitToPageEnabled: false,
      duplex: 0,
      copies: 1,
      collate: true,
      shouldPrintBackgrounds: false,
      shouldPrintSelectionOnly: false
    }
    if (options.landscape) {
      printingSetting.landscape = options.landscape
    }
    if (options.marginsType) {
      printingSetting.marginsType = options.marginsType
    }
    if (options.printSelectionOnly) {
      printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly
    }
    if (options.printBackground) {
      printingSetting.shouldPrintBackgrounds = options.printBackground
    }

    if (options.pageSize) {
      let height = 0
      let width = 0
      if (typeof options.pageSize === 'object') {
        // Dimensions in Microns
        // 1 meter = 10^6 microns
        height = options.pageSize.height ? options.pageSize.height : 0
        width = options.pageSize.width ? options.pageSize.width : 0
      }

      if (height > 0 && width > 0) {
        printingSetting.mediaSize = {
          height_microns: height,
          name: 'CUSTOM',
          width_microns: width,
          custom_display_name: 'Custom'
        }
      } else if (PDFPageSize[options.pageSize]) {
        printingSetting.mediaSize = PDFPageSize[options.pageSize]
      } else {
        printingSetting.mediaSize = PDFPageSize['A4']
      }
    }

    return this._printToPDF(printingSetting, callback)
  }
}

binding._setWrapWebContents(wrapWebContents)

// Add JavaScript wrappers for Debugger class.
const wrapDebugger = function (webContentsDebugger) {
  // debugger is an EventEmitter.
  Object.setPrototypeOf(webContentsDebugger, EventEmitter.prototype)
}

debuggerBinding._setWrapDebugger(wrapDebugger)

module.exports = {
  create (options = {}) {
    return binding.create(options)
  },

  fromId (id) {
    return binding.fromId(id)
  }
}
<commit_msg>Cleanup the printToPDF code<commit_after>'use strict'

const {EventEmitter} = require('events')
const {ipcMain, session, Menu, NavigationController} = require('electron')

// session is not used here, the purpose is to make sure session is initalized
// before the webContents module.
session

const binding = process.atomBinding('web_contents')
const debuggerBinding = process.atomBinding('debugger')

let nextId = 0
const getNextId = function () {
  return ++nextId
}

// Stock page sizes
const PDFPageSizes = {
  A5: {
    custom_display_name: 'A5',
    height_microns: 210000,
    name: 'ISO_A5',
    width_microns: 148000
  },
  A4: {
    custom_display_name: 'A4',
    height_microns: 297000,
    name: 'ISO_A4',
    is_default: 'true',
    width_microns: 210000
  },
  A3: {
    custom_display_name: 'A3',
    height_microns: 420000,
    name: 'ISO_A3',
    width_microns: 297000
  },
  Legal: {
    custom_display_name: 'Legal',
    height_microns: 355600,
    name: 'NA_LEGAL',
    width_microns: 215900
  },
  Letter: {
    custom_display_name: 'Letter',
    height_microns: 279400,
    name: 'NA_LETTER',
    width_microns: 215900
  },
  Tabloid: {
    height_microns: 431800,
    name: 'NA_LEDGER',
    width_microns: 279400,
    custom_display_name: 'Tabloid'
  }
}

// Default printing setting
const defaultPrintingSetting = {
  pageRage: [],
  mediaSize: {},
  landscape: false,
  color: 2,
  headerFooterEnabled: false,
  marginsType: 0,
  isFirstRequest: false,
  requestID: getNextId(),
  previewModifiable: true,
  printToPDF: true,
  printWithCloudPrint: false,
  printWithPrivet: false,
  printWithExtension: false,
  deviceName: 'Save as PDF',
  generateDraftData: true,
  fitToPageEnabled: false,
  duplex: 0,
  copies: 1,
  collate: true,
  shouldPrintBackgrounds: false,
  shouldPrintSelectionOnly: false
}

// Following methods are mapped to webFrame.
const webFrameMethods = [
  'insertText',
  'setZoomFactor',
  'setZoomLevel',
  'setZoomLevelLimits'
]

// Add JavaScript wrappers for WebContents class.
const wrapWebContents = function (webContents) {
  // webContents is an EventEmitter.
  Object.setPrototypeOf(webContents, EventEmitter.prototype)

  // Every remote callback from renderer process would add a listenter to the
  // render-view-deleted event, so ignore the listenters warning.
  webContents.setMaxListeners(0)

  // WebContents::send(channel, args..)
  // WebContents::sendToAll(channel, args..)
  const sendWrapper = (allFrames, channel, ...args) => {
    if (channel == null) {
      throw new Error('Missing required channel argument')
    }
    return webContents._send(allFrames, channel, args)
  }
  webContents.send = sendWrapper.bind(null, false)
  webContents.sendToAll = sendWrapper.bind(null, true)

  // The navigation controller.
  const controller = new NavigationController(webContents)
  for (const name in NavigationController.prototype) {
    const method = NavigationController.prototype[name]
    if (method instanceof Function) {
      webContents[name] = function () {
        return method.apply(controller, arguments)
      }
    }
  }

  // Mapping webFrame methods.
  for (const method of webFrameMethods) {
    webContents[method] = function (...args) {
      this.send('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, args)
    }
  }

  const asyncWebFrameMethods = function (requestId, method, callback, ...args) {
    this.send('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args)
    ipcMain.once(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, function (event, result) {
      if (callback) callback(result)
    })
  }

  // Make sure webContents.executeJavaScript would run the code only when the
  // webContents has been loaded.
  webContents.executeJavaScript = function (code, hasUserGesture, callback) {
    const requestId = getNextId()
    if (typeof hasUserGesture === 'function') {
      callback = hasUserGesture
      hasUserGesture = false
    }
    if (this.getURL() && !this.isLoadingMainFrame()) {
      asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)
    } else {
      this.once('did-finish-load', () => {
        asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)
      })
    }
  }

  // Dispatch IPC messages to the ipc module.
  webContents.on('ipc-message', function (event, [channel, ...args]) {
    ipcMain.emit(channel, event, ...args)
  })
  webContents.on('ipc-message-sync', function (event, [channel, ...args]) {
    Object.defineProperty(event, 'returnValue', {
      set: function (value) {
        return event.sendReply(JSON.stringify(value))
      },
      get: function () {}
    })
    ipcMain.emit(channel, event, ...args)
  })

  // Handle context menu action request from pepper plugin.
  webContents.on('pepper-context-menu', function (event, params) {
    const menu = Menu.buildFromTemplate(params.menu)
    menu.popup(params.x, params.y)
  })

  // The devtools requests the webContents to reload.
  webContents.on('devtools-reload-page', function () {
    webContents.reload()
  })

  // Delays the page-title-updated event to next tick.
  webContents.on('-page-title-updated', function (...args) {
    setImmediate(() => {
      this.emit.apply(this, ['page-title-updated'].concat(args))
    })
  })

  webContents.printToPDF = function (options, callback) {
    const printingSetting = Object.assign({}, defaultPrintingSetting)
    if (options.landscape) {
      printingSetting.landscape = options.landscape
    }
    if (options.marginsType) {
      printingSetting.marginsType = options.marginsType
    }
    if (options.printSelectionOnly) {
      printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly
    }
    if (options.printBackground) {
      printingSetting.shouldPrintBackgrounds = options.printBackground
    }

    if (options.pageSize) {
      const pageSize = options.pageSize
      if (typeof pageSize === 'object') {
        if (!pageSize.height || !pageSize.width) {
          return callback(new Error('Must define height and width for pageSize'))
        }
        // Dimensions in Microns
        // 1 meter = 10^6 microns
        printingSetting.mediaSize = {
          name: 'CUSTOM',
          custom_display_name: 'Custom',
          height_microns: pageSize.height,
          width_microns: pageSize.width
        }
      } else if (PDFPageSizes[pageSize]) {
        printingSetting.mediaSize = PDFPageSizes[pageSize]
      } else {
        return callback(new Error(`Does not support pageSize with ${pageSize}`))
      }
    } else {
      printingSetting.mediaSize = PDFPageSizes['A4']
    }

    this._printToPDF(printingSetting, callback)
  }
}

binding._setWrapWebContents(wrapWebContents)

// Add JavaScript wrappers for Debugger class.
const wrapDebugger = function (webContentsDebugger) {
  // debugger is an EventEmitter.
  Object.setPrototypeOf(webContentsDebugger, EventEmitter.prototype)
}

debuggerBinding._setWrapDebugger(wrapDebugger)

module.exports = {
  create (options = {}) {
    return binding.create(options)
  },

  fromId (id) {
    return binding.fromId(id)
  }
}
<|endoftext|>


<commit_before>//[media]
// Uncomment the previous line for testing on webpagetest.org

// Sanitize the `attributes` property.
function getNodeAttributes(node) {
  // Inspired by dequelabs/axe-core.
  if (node.attributes instanceof NamedNodeMap) {
    return node.attributes;
  }
  return node.cloneNode(false).attributes;
}

// Map nodes to their attributes,
function parseNodes(nodes) {
  var parsedNodes = [];
  if (nodes) {
    for (var i = 0, len = nodes.length; i < len; i++) {
      var node = nodes[i];
      var attributes = Object.values(getNodeAttributes(node));
      var el = {};

      el.tagName = node.tagName.toLowerCase(); // for reference
      for (var n = 0, len2 = attributes.length; n < len2; n++) {
        var attribute = attributes[n];
        el[attribute.name.toLowerCase()] = attribute.value;
      }

      parsedNodes.push(el);
    }
  }
  return parsedNodes;
}

// Return the set of attributes for nodes,
function getNodesAttributes(nodes) {
  if (!nodes) {
    return [];
  }
  var uniqueAttributes = new Set();
  for (var node of nodes) {
    var attributes = Object.values(getNodeAttributes(node));
    for (var attribute of attributes) {
      uniqueAttributes.add(attribute.name.toLowerCase());
    }
  }
  return Array.from(uniqueAttributes);
}

return JSON.stringify({
  // Counts the number of picture tags containing an img tag
  'num_picture_img': document.querySelectorAll('picture img').length,
  // Counts the number of source or img tags with sizes attribute
  'num_image_sizes': document.querySelectorAll('source[sizes], img[sizes]').length,
  // Count the mumber of images with srcset attribute
  'num_srcset_all': document.querySelectorAll('source[srcset], img[srcset]').length,
  // Count the mumber of images with srcset and sizes attributes
  'num_srcset_sizes': document.querySelectorAll('source[srcset][sizes], img[srcset][sizes]').length,
  // Count the number of imges with srcset with descriptor-x
  'num_srcset_descriptor_x': (() => {
    var nodes = document.querySelectorAll('source[srcset], img[srcset]');
    return Array.from(nodes).filter(node => node.getAttribute('srcset').match(/\s\d+x/)).length;
  })(),
  // Count the number of imges with srcset with descriptor-w
  'num_srcset_descriptor_w': (() => {
    var nodes = document.querySelectorAll('source[srcset], img[srcset]');
    return Array.from(nodes).filter(node => node.getAttribute('srcset').match(/\s\d+w/)).length;
  })(),
  // Count the number of scrset candidates
  'num_srcset_candidates': (() => {
    var nodes = document.querySelectorAll('source[srcset], img[srcset]');
    var count = 0;
    for (var i = 0, len = nodes.length; i < len; i++) {
      var srcset = nodes[i].getAttribute('srcset');
      if (!srcset) {
        continue;
      }
      count += srcset.split(',').length;
    }
    return count;
  })(),
  // Return picture formats ["image/webp","image/svg+xml"]
  'picture_formats': (() => {
    var nodes = document.querySelectorAll('picture source[type]');
    var formats = new Set();
    for (var source of nodes) {
      var format = source.getAttribute('type');
      if (!format) {
        continue;
      }
      formats.add(format.toLowerCase());
    }
    return Array.from(formats);
  })(),
  // Count all video nodes
  'num_video_nodes': document.querySelectorAll('video').length,
  // Returns a set of video node attribute names
  'video_nodes_attributes': (() => {
    var allAttributes = getNodesAttributes(document.querySelectorAll('video'));
    var filter = ['autoplay', 'autoPictureInPicture', 'buffered', 'controls',
      'controlslist', 'crossorigin', 'use-credentials', 'currentTime',
      'disablePictureInPicture', 'disableRemotePlayback', 'duration',
      'height', 'intrinsicsize', 'loop', 'muted', 'playsinline', 'poster',
      'preload', 'src', 'width'];
    return allAttributes.filter(el => filter.includes(el));
  })(),
  // Counts the number of pictures using source media min-resolution
  'num_picture_using_min_resolution': (() => {
    var pictures = document.querySelectorAll('picture');
    return Array.from(pictures).filter(picture => {
      return picture.querySelector('source[media*="min-resolution"]');
    }).length;
  })(),
  // Counts the number of pictures using source media orientation
  'num_picture_using_orientation': (() => {
    var pictures = document.querySelectorAll('picture');
    return Array.from(pictures).filter(picture => {
      return picture.querySelector('source[media*="orientation"]');
    }).length;
  })(),
  // Counts the number of candidates for srcset of img that are not in picture
  'num_img_not_in_picture_srcset_candidates': (() => {
    var images = document.querySelectorAll('img[srcset]');
    var nodes = Array.from(images).filter(image => {
      return image.parentNode.tagName.toLowerCase() != 'picture';
    });
    var count = 0;
    for (var node of nodes) {
      var srcset = node.getAttribute('srcset');
      if (!srcset) {
        continue;
      }
      count += srcset.split(',').length;
    }
    return count;
  })()
});
<commit_msg>Media 2021 custom metrics (#215)<commit_after>//[media]
// Uncomment the previous line for testing on webpagetest.org

// Sanitize the `attributes` property.
function getNodeAttributes(node) {
  // Inspired by dequelabs/axe-core.
  if (node.attributes instanceof NamedNodeMap) {
    return node.attributes;
  }
  return node.cloneNode(false).attributes;
}

// Map nodes to their attributes,
function parseNodes(nodes) {
  var parsedNodes = [];
  if (nodes) {
    for (var i = 0, len = nodes.length; i < len; i++) {
      var node = nodes[i];
      var attributes = Object.values(getNodeAttributes(node));
      var el = {};

      el.tagName = node.tagName.toLowerCase(); // for reference
      for (var n = 0, len2 = attributes.length; n < len2; n++) {
        var attribute = attributes[n];
        el[attribute.name.toLowerCase()] = attribute.value;
      }

      parsedNodes.push(el);
    }
  }
  return parsedNodes;
}

// Return the set of attributes for nodes,
function getNodesAttributes(nodes) {
  if (!nodes) {
    return [];
  }
  var uniqueAttributes = new Set();
  for (var node of nodes) {
    var attributes = Object.values(getNodeAttributes(node));
    for (var attribute of attributes) {
      uniqueAttributes.add(attribute.name.toLowerCase());
    }
  }
  return Array.from(uniqueAttributes);
}

return JSON.stringify({
  // Counts the number of picture tags containing an img tag
  'num_picture_img': document.querySelectorAll('picture img').length,
  // Counts the number of source or img tags with sizes attribute
  'num_image_sizes': document.querySelectorAll('source[sizes], img[sizes]').length,
  // Count the mumber of images with srcset attribute
  'num_srcset_all': document.querySelectorAll('source[srcset], img[srcset]').length,
  // Count the mumber of images with srcset and sizes attributes
  'num_srcset_sizes': document.querySelectorAll('source[srcset][sizes], img[srcset][sizes]').length,
  // Count the number of imges with srcset with descriptor-x
  'num_srcset_descriptor_x': (() => {
    var nodes = document.querySelectorAll('source[srcset], img[srcset]');
    return Array.from(nodes).filter(node => node.getAttribute('srcset').match(/\s\d+x/)).length;
  })(),
  // Count the number of imges with srcset with descriptor-w
  'num_srcset_descriptor_w': (() => {
    var nodes = document.querySelectorAll('source[srcset], img[srcset]');
    return Array.from(nodes).filter(node => node.getAttribute('srcset').match(/\s\d+w/)).length;
  })(),
  // Count the number of scrset candidates
  'num_srcset_candidates': (() => {
    var nodes = document.querySelectorAll('source[srcset], img[srcset]');
    var count = 0;
    for (var i = 0, len = nodes.length; i < len; i++) {
      var srcset = nodes[i].getAttribute('srcset');
      if (!srcset) {
        continue;
      }
      count += srcset.split(',').length;
    }
    return count;
  })(),
  // Return picture formats ["image/webp","image/svg+xml"]
  'picture_formats': (() => {
    var nodes = document.querySelectorAll('picture source[type]');
    var formats = new Set();
    for (var source of nodes) {
      var format = source.getAttribute('type');
      if (!format) {
        continue;
      }
      formats.add(format.toLowerCase());
    }
    return Array.from(formats);
  })(),
  // Count all video nodes
  'num_video_nodes': document.querySelectorAll('video').length,

  //gets the duration of all videos
  'video_durations': (() =>{
    return Array.from(document.querySelectorAll('video')).map(video => video.duration);
  })(),

    // Returns a set of video node attribute names, and the count on the page
    'video_attributes_values_counts': Array.from(document.querySelectorAll('video')).reduce((stats, video) => {
      const attrs = video.getAttributeNames();
      var filter = ['autoplay', 'autoPictureInPicture', 'buffered', 'controls',
      'controlslist', 'crossorigin', 'use-credentials', 'currentTime',
      'disablePictureInPicture', 'disableRemotePlayback', 'duration',
      'height', 'intrinsicsize', 'loop', 'muted', 'playsinline', 'poster',
      'preload', 'src', 'width'];
      attrs.map(attr => attr.toLowerCase()).filter(attr => filter.includes(attr)).forEach(attr => {
        const value = video.getAttribute(attr);
        let stat = stats.find(stat => stat.attribute == attr && stat.value == value);
        if (!stat) {
          stat = {attribute: attr, value, count: 0};
          stats.push(stat);
        }
        stat.count++;
      });
      return stats;
    }, []),
    //Returns the CSS display style for a video tag
    //many mobile sites use display:none to 'hide' the video, but it still gets downloaded
    'video_display_style' : Array.from(document.querySelectorAll('video')).map(video => {
      return getComputedStyle(video, null).getPropertyValue('display');
    }),
    //returns an array of the number of source files per video tag.
    'video_source_format_count': Array.from(document.querySelectorAll('video')).map(video => video.querySelectorAll('source').length),
    //Returns all of the video types for each source file
    'video_source_format_type': Array.from(document.querySelectorAll('video')).map(video => {
      return Array.from(video.querySelectorAll('source')).map(source => {
        return source.getAttribute('type')
      });
    }),
  // Counts the number of pictures using source media min-resolution
  'num_picture_using_min_resolution': (() => {
    var pictures = document.querySelectorAll('picture');
    return Array.from(pictures).filter(picture => {
      return picture.querySelector('source[media*="min-resolution"]');
    }).length;
  })(),
  // Counts the number of pictures using source media orientation
  'num_picture_using_orientation': (() => {
    var pictures = document.querySelectorAll('picture');
    return Array.from(pictures).filter(picture => {
      return picture.querySelector('source[media*="orientation"]');
    }).length;
  })(),
  // Counts the number of candidates for srcset of img that are not in picture
  'num_img_not_in_picture_srcset_candidates': (() => {
    var images = document.querySelectorAll('img[srcset]');
    var nodes = Array.from(images).filter(image => {
      return image.parentNode.tagName.toLowerCase() != 'picture';
    });
    var count = 0;
    for (var node of nodes) {
      var srcset = node.getAttribute('srcset');
      if (!srcset) {
        continue;
      }
      count += srcset.split(',').length;
    }
    return count;
  })()
});
<|endoftext|>


<commit_before>/*jshint node: true, -W106 */
'use strict';

/*
* Name : graph.js
* Module : Lib::BusinessTier::Graph
* Location : /lib/businessTier/graph
*
* History :
*
* Version   Date         Programmer         Description
* =========================================================
* 0.0.1     2015-05-20   Filippo Rampado    Initial code
* =========================================================
*/

/*var Socket=require('../../presentationTier/socket.js');
var Page=require('../page/page.js');*/
function Graph(page, graphSocket) {
	console.log('Piedino4-1');
	if (page===undefined || !(page.hasOwnProperty('_page'))){
		console.log('Error: 302');
		return;
	}
	console.log('Piedino4-2');
	if (graphSocket===undefined || !(graphSocket.hasOwnProperty('_namespace'))){
		console.log('Error: 301');
		return;
	}
	console.log('Piedino4-3');
	this._page=page;
	this._graphSocket=graphSocket;

	this._graphSocket.attachObject(this, 'configGraph');
}

module.exports = Graph;
<commit_msg>remove log<commit_after>/*jshint node: true, -W106 */
'use strict';

/*
* Name : graph.js
* Module : Lib::BusinessTier::Graph
* Location : /lib/businessTier/graph
*
* History :
*
* Version   Date         Programmer         Description
* =========================================================
* 0.0.1     2015-05-20   Filippo Rampado    Initial code
* =========================================================
*/

/*var Socket=require('../../presentationTier/socket.js');
var Page=require('../page/page.js');*/
function Graph(page, graphSocket) {
	if (page===undefined || !(page.hasOwnProperty('_page'))){
		console.log('Error: 302');
		return;
	}
	if (graphSocket===undefined || !(graphSocket.hasOwnProperty('_namespace'))){
		console.log('Error: 301');
		return;
	}
	this._page=page;
	this._graphSocket=graphSocket;

	this._graphSocket.attachObject(this, 'configGraph');
}

module.exports = Graph;
<|endoftext|>