<commit_before>'use strict';

angular.module('rain.ui.services', []).service('ui_services', function()
{
  this.update_background = function(element, background_image)
  {
    var background = $(element).find('.background-image-holder');
    background.css('background', 'url("' + background_image + '")');
    background.children('img').hide();
    background.css('background-position', 'initial');
  };

  this.navbar_fixer = function(element, nav_properties)
  {
    var navbar = $(element).find('nav');
    var first_section_height = $('.main-container section:nth-of-type(1)').outerHeight(true);
    var nav_outer_height = $('body .nav-container nav:first').outerHeight();

    var scroll_y = window.pageYOffset;

    if (scroll_y <= 0)
    {
      if (nav_properties.nav_fixed)
      {
        nav_properties.nav_fixed = false;
        navbar.removeClass('fixed');
      }
      if (nav_properties.nav_out_of_sight)
      {
        nav_properties.nav_out_of_sight = false;
        navbar.removeClass('outOfSight');
      }
      if (nav_properties.nav_scrolled)
      {
        nav_properties.nav_scrolled = false;
        navbar.removeClass('scrolled');
      }
      return;
    }

    if (scroll_y > first_section_height)
    {
      if (!nav_properties.nav_scrolled)
      {
        navbar.addClass('scrolled');
        nav_properties.nav_scrolled = true;
        return;
      }
    }
    else
    {
      if (scroll_y > nav_outer_height)
      {
        if (!nav_properties.nav_fixed)
        {
          navbar.addClass('fixed');
          nav_properties.nav_fixed = true;
        }

        if (scroll_y > nav_outer_height * 2)
        {
          if(!nav_properties.nav_out_of_sight)
          {
            navbar.addClass('outOfSight');
            nav_properties.nav_out_of_sight = true;
          }
        }
        else
        {
          if (nav_properties.nav_out_of_sight)
          {
            nav_properties.nav_out_of_sight = false;
            navbar.removeClass('outOfSight');
          }
        }
      }
      else
      {
        if (nav_properties.nav_fixed)
        {
          nav_properties.nav_fixed = false;
          navbar.removeClass('fixed');
        }
        if (nav_properties.nav_out_of_sight)
        {
          nav_properties.nav_out_of_sight = false;
          navbar.removeClass('outOfSight');
        }
      }

      if (nav_properties.nav_scrolled)
      {
        nav_properties.nav_scrolled = false;
        navbar.removeClass('scrolled');
      }
    }
  };

  this.navbar_setup = function(element)
  {
    var nav = element.find('nav');

    if (!nav.hasClass('fixed') && !nav.hasClass('absolute'))
    {
      // Make nav container height of nav
      nav.css('min-height', $('nav').outerHeight(true));

      if ($(window).width() > 768)
        $('.parallax:nth-of-type(1) .background-image-holder').css('top', -($('nav').outerHeight(true)));

      // Adjust fullscreen elements
      if ($(window).width() > 768)
        $('section.fullscreen:nth-of-type(1)').css('height', ($(window).height() - $('nav').outerHeight(true)));
    }
    else
    {
      $('body').addClass('nav-is-overlay');

    }

    if (nav.hasClass('bg-dark'))
      element.addClass('bg-dark');

    // Fix nav to top while scrolling
    //mr_navOuterHeight = $('body .nav-container nav:first').outerHeight();

    $('.search-widget-handle .search-form input').click(function(e)
    {
      if (!e) e = window.event;
      e.stopPropagation();
    });

    // Offscreen Nav

    if($('.offscreen-toggle').length)
      $('body').addClass('has-offscreen-nav');
    else
        $('body').removeClass('has-offscreen-nav');

    $('.offscreen-toggle').click(function()
    {
      $('.main-container').toggleClass('reveal-nav');
      $('nav').toggleClass('reveal-nav');
      $('.offscreen-container').toggleClass('reveal-nav');
    });

    $('.main-container').click(function()
    {
      if($(this).hasClass('reveal-nav'))
      {
        $(this).removeClass('reveal-nav');
        $('.offscreen-container').removeClass('reveal-nav');
        $('nav').removeClass('reveal-nav');
      }
    });

    $('.offscreen-container a').click(function()
    {
      $('.offscreen-container').removeClass('reveal-nav');
      $('.main-container').removeClass('reveal-nav');
      $('nav').removeClass('reveal-nav');
    });

    // Mobile Menu
    $(element).find('.mobile-toggle').click(function()
    {
      $(element).find('.nav-bar').toggleClass('nav-open');
      $(this).toggleClass('active');
    });
  };

  this.navbar_dropdown_setup = function(element)
  {
    // Dropdown positioning
    $(element).find('.menu>li>ul').each(function()
    {
      var menu = $(this).offset();
      var farRight = menu.left + $(this).outerWidth(true);
      if (farRight > $(window).width() && !$(this).hasClass('mega-menu'))
        $(this).addClass('make-right');
      else if (farRight > $(window).width() && $(this).hasClass('mega-menu'))
      {
        var isOnScreen = $(window).width() - menu.left;
        var difference = $(this).outerWidth(true) - isOnScreen;
        $(this).css('margin-left', -(difference));
      }
    });

    // Nested menus
    $(element).find('.menu').click(function(e)
    {
      if (!e) e = window.event;
      e.stopPropagation();
      if ($(this).find('ul').length)
        $(this).toggleClass('toggle-sub');
      else
        $(this).parents('.toggle-sub').removeClass('toggle-sub');
    });

    $(element).find('.menu>li>a').click(function()
    {
      //if ($(this).hasClass('inner-link'))
      $(this).parents('.nav-bar').removeClass('nav-open');
    });

    // Don't know if really useful (no behaviour revealed)
    // css for toggle-widget-handle:
    //  display: block !important;

    $(element).find('.module.widget-handle').click(function()
    {
      $(this).toggleClass('toggle-widget-handle');
    });
  };

  this.parallax_handler = function()
  {
    // Disable parallax on mobile
    if ((/Android|iPhone|iPad|iPod|BlackBerry|Windows Phone/i).test(navigator.userAgent || navigator.vendor || window.opera))
      $('section').removeClass('parallax');
  };

  this.slider_setup = function(element)
  {
    element.find('.slider-all-controls').flexslider({
      start: function(slider)
      {
        if(slider.find('.slides li:first-child').find('.fs-vid-background video').length)
          slider.find('.slides li:first-child').find('.fs-vid-background video').get(0).play();
      },
      after: function(slider)
      {
        if(slider.find('.fs-vid-background video').length)
        {
          if(slider.find('li:not(.flex-active-slide)').find('.fs-vid-background video').length)
            slider.find('li:not(.flex-active-slide)').find('.fs-vid-background video').get(0).pause();

          if(slider.find('.flex-active-slide').find('.fs-vid-background video').length)
            slider.find('.flex-active-slide').find('.fs-vid-background video').get(0).play();
        }
      }
    });

    element.find('.slider-paging-controls').flexslider({
      animation: 'slide',
      directionNav: false
    });

    element.find('.slider-arrow-controls').flexslider({
      controlNav: false
    });

    element.find('.slider-thumb-controls .slides li').each(function()
    {
      var imgSrc = $(this).find('img').attr('src');
      $(this).attr('data-thumb', imgSrc);
    });

    element.find('.slider-thumb-controls').flexslider({
      animation: 'slide',
      controlNav: 'thumbnails',
      directionNav: true
    });

    element.find('.logo-carousel').flexslider({
      minItems: 1,
      maxItems: 4,
      move: 1,
      itemWidth: 200,
      itemMargin: 0,
      animation: 'slide',
      slideshow: true,
      slideshowSpeed: 3000,
      directionNav: false,
      controlNav: false
    });

    var setUpTweets = setInterval(function()
    {
      if ($('.tweets-slider').find('li.flex-active-slide').length)
      {
        clearInterval(setUpTweets);
        return;
      }
      else
      {
        if ($('.tweets-slider').length)
        {
          $('.tweets-slider').flexslider({
            directionNav: false,
            controlNav: false
          });
        }
      }
    }, 500);
  };

  this.inner_link_setup = function(element)
  {
    var link = $(element).find('.inner-link');
    var offset = 1;

    var link_nodes = $('.inner-link');
    for(var i = 0; i < link_nodes.length; i++)
      if(link_nodes[i].classList.contains('back-to-top') && !link_nodes[i].classList.contains('floating'))
        link_nodes[i].addEventListener('click', function()
        {
          $(document).find('.back-to-top.floating').addClass('forced-hidden');
        });

    if(link.length)
    {
      if(link.attr('href') == '#top') offset = 0;
      link.smoothScroll({
        offset: offset,
        speed: 1000
      });
    }
  };

  this.section_height_setup = function(element, children, offset)
  {
    var dim = offset;
    children.each(function()
    {
      dim += $(this).outerHeight();
    });
    element.css('min-height', dim);
  };

  this.floating_back_to_top_show = function(element)
  {
    var first_section_height = $('.main-container section:nth-of-type(1)').outerHeight(true);
    var last_section_position = $('.main-container section:nth-last-of-type(1)').offset().top;
    var last_section_height = $('.main-container section:nth-last-of-type(1)').outerHeight(true);
    var scroll_y = window.pageYOffset;
    if(scroll_y < first_section_height)
    {
      element.find('.back-to-top').removeClass('forced-hidden');
      element.find('.back-to-top').removeClass('visible');
    }
    else if(scroll_y > first_section_height && scroll_y + window.innerHeight <= last_section_position + last_section_height)
    {
      element.find('.back-to-top').addClass('visible');
    }
    else
    {
      element.find('.back-to-top').removeClass('visible');
    }
  };

  this.modal_strip_setup = function(element)
  {
    if(!element.find('.close-modal').length)
      element.append($('<i class="ti-close close-modal">'));

    if(typeof element.attr('data-cookie') !== "undefined")
    {
      if(!mr_cookies.hasItem(element.attr('data-cookie')))
        setTimeout(function()
        {
          element.addClass('reveal-modal');
        },1000);
    }
    else
      setTimeout(function()
      {
        element.addClass('reveal-modal');
      },1000);

    $('.modal-strip .close-modal').click(function()
    {
      console.log("esco");
      var modal = element.closest('.modal-strip');
      if(typeof modal.attr('data-cookie') != "undefined")
      {
        mr_cookies.setItem(modal.attr('data-cookie'), "true", Infinity);
      }
      element.closest('.modal-strip').removeClass('reveal-modal');
      return false;
    });
  }
});
<commit_msg>Extended the floating back-to-top fade to all links.<commit_after>'use strict';

angular.module('rain.ui.services', []).service('ui_services', function()
{
  this.update_background = function(element, background_image)
  {
    var background = $(element).find('.background-image-holder');
    background.css('background', 'url("' + background_image + '")');
    background.children('img').hide();
    background.css('background-position', 'initial');
  };

  this.navbar_fixer = function(element, nav_properties)
  {
    var navbar = $(element).find('nav');
    var first_section_height = $('.main-container section:nth-of-type(1)').outerHeight(true);
    var nav_outer_height = $('body .nav-container nav:first').outerHeight();

    var scroll_y = window.pageYOffset;

    if (scroll_y <= 0)
    {
      if (nav_properties.nav_fixed)
      {
        nav_properties.nav_fixed = false;
        navbar.removeClass('fixed');
      }
      if (nav_properties.nav_out_of_sight)
      {
        nav_properties.nav_out_of_sight = false;
        navbar.removeClass('outOfSight');
      }
      if (nav_properties.nav_scrolled)
      {
        nav_properties.nav_scrolled = false;
        navbar.removeClass('scrolled');
      }
      return;
    }

    if (scroll_y > first_section_height)
    {
      if (!nav_properties.nav_scrolled)
      {
        navbar.addClass('scrolled');
        nav_properties.nav_scrolled = true;
        return;
      }
    }
    else
    {
      if (scroll_y > nav_outer_height)
      {
        if (!nav_properties.nav_fixed)
        {
          navbar.addClass('fixed');
          nav_properties.nav_fixed = true;
        }

        if (scroll_y > nav_outer_height * 2)
        {
          if(!nav_properties.nav_out_of_sight)
          {
            navbar.addClass('outOfSight');
            nav_properties.nav_out_of_sight = true;
          }
        }
        else
        {
          if (nav_properties.nav_out_of_sight)
          {
            nav_properties.nav_out_of_sight = false;
            navbar.removeClass('outOfSight');
          }
        }
      }
      else
      {
        if (nav_properties.nav_fixed)
        {
          nav_properties.nav_fixed = false;
          navbar.removeClass('fixed');
        }
        if (nav_properties.nav_out_of_sight)
        {
          nav_properties.nav_out_of_sight = false;
          navbar.removeClass('outOfSight');
        }
      }

      if (nav_properties.nav_scrolled)
      {
        nav_properties.nav_scrolled = false;
        navbar.removeClass('scrolled');
      }
    }
  };

  this.navbar_setup = function(element)
  {
    var nav = element.find('nav');

    if (!nav.hasClass('fixed') && !nav.hasClass('absolute'))
    {
      // Make nav container height of nav
      nav.css('min-height', $('nav').outerHeight(true));

      if ($(window).width() > 768)
        $('.parallax:nth-of-type(1) .background-image-holder').css('top', -($('nav').outerHeight(true)));

      // Adjust fullscreen elements
      if ($(window).width() > 768)
        $('section.fullscreen:nth-of-type(1)').css('height', ($(window).height() - $('nav').outerHeight(true)));
    }
    else
    {
      $('body').addClass('nav-is-overlay');

    }

    if (nav.hasClass('bg-dark'))
      element.addClass('bg-dark');

    // Fix nav to top while scrolling
    //mr_navOuterHeight = $('body .nav-container nav:first').outerHeight();

    $('.search-widget-handle .search-form input').click(function(e)
    {
      if (!e) e = window.event;
      e.stopPropagation();
    });

    // Offscreen Nav

    if($('.offscreen-toggle').length)
      $('body').addClass('has-offscreen-nav');
    else
        $('body').removeClass('has-offscreen-nav');

    $('.offscreen-toggle').click(function()
    {
      $('.main-container').toggleClass('reveal-nav');
      $('nav').toggleClass('reveal-nav');
      $('.offscreen-container').toggleClass('reveal-nav');
    });

    $('.main-container').click(function()
    {
      if($(this).hasClass('reveal-nav'))
      {
        $(this).removeClass('reveal-nav');
        $('.offscreen-container').removeClass('reveal-nav');
        $('nav').removeClass('reveal-nav');
      }
    });

    $('.offscreen-container a').click(function()
    {
      $('.offscreen-container').removeClass('reveal-nav');
      $('.main-container').removeClass('reveal-nav');
      $('nav').removeClass('reveal-nav');
    });

    // Mobile Menu
    $(element).find('.mobile-toggle').click(function()
    {
      $(element).find('.nav-bar').toggleClass('nav-open');
      $(this).toggleClass('active');
    });
  };

  this.navbar_dropdown_setup = function(element)
  {
    // Dropdown positioning
    $(element).find('.menu>li>ul').each(function()
    {
      var menu = $(this).offset();
      var farRight = menu.left + $(this).outerWidth(true);
      if (farRight > $(window).width() && !$(this).hasClass('mega-menu'))
        $(this).addClass('make-right');
      else if (farRight > $(window).width() && $(this).hasClass('mega-menu'))
      {
        var isOnScreen = $(window).width() - menu.left;
        var difference = $(this).outerWidth(true) - isOnScreen;
        $(this).css('margin-left', -(difference));
      }
    });

    // Nested menus
    $(element).find('.menu').click(function(e)
    {
      if (!e) e = window.event;
      e.stopPropagation();
      if ($(this).find('ul').length)
        $(this).toggleClass('toggle-sub');
      else
        $(this).parents('.toggle-sub').removeClass('toggle-sub');
    });

    $(element).find('.menu>li>a').click(function()
    {
      //if ($(this).hasClass('inner-link'))
      $(this).parents('.nav-bar').removeClass('nav-open');
    });

    // Don't know if really useful (no behaviour revealed)
    // css for toggle-widget-handle:
    //  display: block !important;

    $(element).find('.module.widget-handle').click(function()
    {
      $(this).toggleClass('toggle-widget-handle');
    });
  };

  this.parallax_handler = function()
  {
    // Disable parallax on mobile
    if ((/Android|iPhone|iPad|iPod|BlackBerry|Windows Phone/i).test(navigator.userAgent || navigator.vendor || window.opera))
      $('section').removeClass('parallax');
  };

  this.slider_setup = function(element)
  {
    element.find('.slider-all-controls').flexslider({
      start: function(slider)
      {
        if(slider.find('.slides li:first-child').find('.fs-vid-background video').length)
          slider.find('.slides li:first-child').find('.fs-vid-background video').get(0).play();
      },
      after: function(slider)
      {
        if(slider.find('.fs-vid-background video').length)
        {
          if(slider.find('li:not(.flex-active-slide)').find('.fs-vid-background video').length)
            slider.find('li:not(.flex-active-slide)').find('.fs-vid-background video').get(0).pause();

          if(slider.find('.flex-active-slide').find('.fs-vid-background video').length)
            slider.find('.flex-active-slide').find('.fs-vid-background video').get(0).play();
        }
      }
    });

    element.find('.slider-paging-controls').flexslider({
      animation: 'slide',
      directionNav: false
    });

    element.find('.slider-arrow-controls').flexslider({
      controlNav: false
    });

    element.find('.slider-thumb-controls .slides li').each(function()
    {
      var imgSrc = $(this).find('img').attr('src');
      $(this).attr('data-thumb', imgSrc);
    });

    element.find('.slider-thumb-controls').flexslider({
      animation: 'slide',
      controlNav: 'thumbnails',
      directionNav: true
    });

    element.find('.logo-carousel').flexslider({
      minItems: 1,
      maxItems: 4,
      move: 1,
      itemWidth: 200,
      itemMargin: 0,
      animation: 'slide',
      slideshow: true,
      slideshowSpeed: 3000,
      directionNav: false,
      controlNav: false
    });

    var setUpTweets = setInterval(function()
    {
      if ($('.tweets-slider').find('li.flex-active-slide').length)
      {
        clearInterval(setUpTweets);
        return;
      }
      else
      {
        if ($('.tweets-slider').length)
        {
          $('.tweets-slider').flexslider({
            directionNav: false,
            controlNav: false
          });
        }
      }
    }, 500);
  };

  this.inner_link_setup = function(element)
  {
    var links = $(element).find('.inner-link');
    var offset = 1;
    var delay = 200;
    var timeout = null;

    links.each(function()
    {
      this.addEventListener('click', function()
      {
        $(document).find('.back-to-top.floating').addClass('forced-hidden');
      });

      window.addEventListener('scroll',function()
      {
        clearTimeout(timeout);
        timeout = setTimeout(function()
        {
          $(document).find('.back-to-top.floating').removeClass('forced-hidden');
        },delay);
      });
    })

    if(links.length)
    {
      if(links.attr('href') === '#top') offset = 0;
      links.smoothScroll(
        {
        offset: offset,
        speed: 1000
      });
    }
  };

  this.section_height_setup = function(element, children, offset)
  {
    var dim = offset;
    children.each(function()
    {
      dim += $(this).outerHeight();
    });
    element.css('min-height', dim);
  };

  this.floating_back_to_top_show = function(element)
  {
    var first_section_height = $('.main-container section:nth-of-type(1)').outerHeight(true);
    var last_section_position = $('.main-container section:nth-last-of-type(1)').offset().top;
    var last_section_height = $('.main-container section:nth-last-of-type(1)').outerHeight(true);
    var scroll_y = window.pageYOffset;
    if(scroll_y < first_section_height)
    {
      element.find('.back-to-top').removeClass('forced-hidden');
      element.find('.back-to-top').removeClass('visible');
    }
    else if(scroll_y > first_section_height && scroll_y + window.innerHeight <= last_section_position + last_section_height)
    {
      element.find('.back-to-top').addClass('visible');
    }
    else
    {
      element.find('.back-to-top').removeClass('visible');
    }
  };

  this.modal_strip_setup = function(element)
  {
    if(!element.find('.close-modal').length)
      element.append($('<i class="ti-close close-modal">'));

    if(typeof element.attr('data-cookie') !== "undefined")
    {
      if(!mr_cookies.hasItem(element.attr('data-cookie')))
        setTimeout(function()
        {
          element.addClass('reveal-modal');
        },1000);
    }
    else
      setTimeout(function()
      {
        element.addClass('reveal-modal');
      },1000);

    $('.modal-strip .close-modal').click(function()
    {
      console.log("esco");
      var modal = element.closest('.modal-strip');
      if(typeof modal.attr('data-cookie') != "undefined")
      {
        mr_cookies.setItem(modal.attr('data-cookie'), "true", Infinity);
      }
      element.closest('.modal-strip').removeClass('reveal-modal');
      return false;
    });
  }
});
<|endoftext|>


<commit_before>export { default as absoluteToChr } from './absolute-to-chr';
export { default as absToChr } from './abs-to-chr';
export { default as chromInfoBisector } from './chrom-info-bisector';
export { default as colorDomainToRgbaArray } from './color-domain-to-rgba-array';
export { default as colorToHex } from './color-to-hex';
export { default as dictFromTuples } from './dict-from-tuples';
export { default as dictItems } from './dict-items';
export { default as dictKeys } from './dict-keys';
export { default as dictValues } from './dict-values';
export { default as download } from './download';
export { default as getTrackByUid } from './get-track-by-uid';
export { default as getTrackPositionByUid } from './get-track-position-by-uid';
export { default as loadChromInfos } from './load-chrom-infos';
export { default as map } from './map';
export { default as objVals } from './obj-vals';
export { default as or } from './or';
export { default as pixelToGenomeLoci } from './pixel-to-genome-loci';
export { default as positionedTracksToAllTracks } from './positioned-tracks-to-all-tracks';
export { default as relToAbsChromPos } from './rel-to-abs-chrom-pos';
export { default as scalesCenterAndK } from './scales-center-and-k';
export { default as scalesToGenomeLoci } from './scales-to-genome-loci';
export { default as sum } from './sum';
<commit_msg>Updatefy<commit_after>export { default as absToChr } from './abs-to-chr';
export { default as chromInfoBisector } from './chrom-info-bisector';
export { default as chrToAbs } from './chr-to-abs';
export { default as colorDomainToRgbaArray } from './color-domain-to-rgba-array';
export { default as colorToHex } from './color-to-hex';
export { default as dictFromTuples } from './dict-from-tuples';
export { default as dictItems } from './dict-items';
export { default as dictKeys } from './dict-keys';
export { default as dictValues } from './dict-values';
export { default as download } from './download';
export { default as genomeLociToPixels } from './genome-loci-to-pixels';
export { default as getTrackByUid } from './get-track-by-uid';
export { default as getTrackPositionByUid } from './get-track-position-by-uid';
export { default as loadChromInfos } from './load-chrom-infos';
export { default as map } from './map';
export { default as objVals } from './obj-vals';
export { default as or } from './or';
export { default as pixelToGenomeLoci } from './pixel-to-genome-loci';
export { default as positionedTracksToAllTracks } from './positioned-tracks-to-all-tracks';
export { default as relToAbsChromPos } from './rel-to-abs-chrom-pos';
export { default as scalesCenterAndK } from './scales-center-and-k';
export { default as scalesToGenomeLoci } from './scales-to-genome-loci';
export { default as sum } from './sum';
<|endoftext|>


<commit_before>import Ember from 'ember';
import WebsocketProxy from 'ember-websockets/helpers/websocket-proxy';

const forEach = Array.prototype.forEach;
const filter  = Array.prototype.filter;
const isArray = Ember.isArray;

export default Ember.Service.extend({
  /*
  * Each element in the array is of the form:
  *
  * {
  *    url: 'string'
  *    socket: WebSocket Proxy object
  * }
  */
  sockets: null,

  init() {
    this._super(...arguments);
    this.sockets = Ember.A();
  },

  /*
  * socketFor returns a websocket proxy object. On this object there is a property `socket`
  * which contains the actual websocket object. This websocket object is cached based off of the url meaning
  * multiple requests for the same socket will return the same object.
  */
  socketFor(url, protocols = []) {
    var proxy = this.findSocketInCache(this.get('sockets'), url);

    if (proxy && this.websocketIsNotClosed(proxy.socket)) { return proxy.socket; }

    // Websockets allows either a string or array of strings to be passed as the second argument.
    // This normalizes both cases into one where they are all arrays of strings and if you just pass
    // a single string it becomes an array of one.
    if(!isArray(protocols)) { protocols = [protocols]; }

    proxy = WebsocketProxy.create({
      content: this,
      protocols: protocols,
      socket: new WebSocket(this.normalizeURL(url), protocols)
    });

    // If there is an existing socket in place we simply update the websocket object and not
    // the whole proxy as we dont want to destroy the previous listeners.
    var existingSocket = this.findSocketInCache(this.get('sockets'), url);
    if(existingSocket) {
      existingSocket.socket.socket = proxy.socket;
      return existingSocket.socket;
    }
    else {
      this.get('sockets').pushObject({
        url: proxy.socket.url,
        socket: proxy
      });
    }

    return proxy;
  },

  /*
  * closeSocketFor closes the socket for a given url.
  */
  closeSocketFor(url) {
    var filteredSockets = [];

    forEach.call(this.get('sockets'), item => {
      if(item.url === this.normalizeURL(url)) {
        item.socket.close();
      }
      else {
        filteredSockets.push(item);
      }
    });

    this.set('sockets', Ember.A(filteredSockets));
  },

  /*
  * The native websocket object will transform urls without a pathname to have just a /.
  * As an example: ws://localhost:8080 would actually be ws://localhost:8080/ but ws://example.com/foo would not
  * change. This function does this transformation to stay inline with the native websocket implementation.
  */
  normalizeURL(url) {
    return url; // FIXME: make a real fix when able to run tests.
    var parsedUrl = new URI(url);
    if(parsedUrl.path() === '/' && url.slice(-1) !== '/') {
      return url + '/';
    }

    return url;
  },

  websocketIsNotClosed(websocket) {
    return websocket.socket.readyState !== window.WebSocket.CLOSED;
  },

  /*
  * Returns the socket object from the cache if one matches the url else undefined
  */
  findSocketInCache(socketsCache, url) {
    var cachedResults = filter.call(socketsCache, websocket => {
      return websocket['url'] === this.normalizeURL(url);
    });

    if(cachedResults.length > 0) {
      return cachedResults[0];
    }
  }
});
<commit_msg>Fix WebsocketsService#normalizeURL method to handle URL with query string correctly<commit_after>import Ember from 'ember';
import WebsocketProxy from 'ember-websockets/helpers/websocket-proxy';

const forEach = Array.prototype.forEach;
const filter  = Array.prototype.filter;
const isArray = Ember.isArray;

export default Ember.Service.extend({
  /*
  * Each element in the array is of the form:
  *
  * {
  *    url: 'string'
  *    socket: WebSocket Proxy object
  * }
  */
  sockets: null,

  init() {
    this._super(...arguments);
    this.sockets = Ember.A();
  },

  /*
  * socketFor returns a websocket proxy object. On this object there is a property `socket`
  * which contains the actual websocket object. This websocket object is cached based off of the url meaning
  * multiple requests for the same socket will return the same object.
  */
  socketFor(url, protocols = []) {
    var proxy = this.findSocketInCache(this.get('sockets'), url);

    if (proxy && this.websocketIsNotClosed(proxy.socket)) { return proxy.socket; }

    // Websockets allows either a string or array of strings to be passed as the second argument.
    // This normalizes both cases into one where they are all arrays of strings and if you just pass
    // a single string it becomes an array of one.
    if(!isArray(protocols)) { protocols = [protocols]; }

    proxy = WebsocketProxy.create({
      content: this,
      protocols: protocols,
      socket: new WebSocket(this.normalizeURL(url), protocols)
    });

    // If there is an existing socket in place we simply update the websocket object and not
    // the whole proxy as we dont want to destroy the previous listeners.
    var existingSocket = this.findSocketInCache(this.get('sockets'), url);
    if(existingSocket) {
      existingSocket.socket.socket = proxy.socket;
      return existingSocket.socket;
    }
    else {
      this.get('sockets').pushObject({
        url: proxy.socket.url,
        socket: proxy
      });
    }

    return proxy;
  },

  /*
  * closeSocketFor closes the socket for a given url.
  */
  closeSocketFor(url) {
    var filteredSockets = [];

    forEach.call(this.get('sockets'), item => {
      if(item.url === this.normalizeURL(url)) {
        item.socket.close();
      }
      else {
        filteredSockets.push(item);
      }
    });

    this.set('sockets', Ember.A(filteredSockets));
  },

  /*
  * The native websocket object will transform urls without a pathname to have just a /.
  * As an example: ws://localhost:8080 would actually be ws://localhost:8080/ but ws://example.com/foo would not
  * change. This function does this transformation to stay inline with the native websocket implementation.
  */
  normalizeURL(url) {
    var parsedUrl = new URI(url);

    if (parsedUrl.path() !== '/') {
      return url;
    }

    var normalizedURL = url;

    if (parsedUrl.query() === '' && url.slice(-1) !== '/') {
      normalizedURL = url + '/';
    } else if (url.indexOf('/?') == -1) {
      normalizedURL = url.replace('?', '/?');
    }

    return normalizedURL;
  },

  websocketIsNotClosed(websocket) {
    return websocket.socket.readyState !== window.WebSocket.CLOSED;
  },

  /*
  * Returns the socket object from the cache if one matches the url else undefined
  */
  findSocketInCache(socketsCache, url) {
    var cachedResults = filter.call(socketsCache, websocket => {
      return websocket['url'] === this.normalizeURL(url);
    });

    if(cachedResults.length > 0) {
      return cachedResults[0];
    }
  }
});
<|endoftext|>


<commit_before>require.config({
	paths: {
		underscore: '../bower_components/underscore/underscore',
		backbone: '../bower_components/backbone/backbone',
		marionette: '../bower_components/backbone.marionette/lib/backbone.marionette',
		jquery: '../bower_components/jquery/jquery',
		localStorage: '../bower_components/backbone.localStorage/backbone.localStorage',
		tpl: 'lib/tpl'
	},

	shim: {
		'lib/backbone-localStorage': ['backbone'],

		underscore: {
			exports: '_'
		},

		backbone: {
			exports: 'Backbone',
			deps: ['jquery', 'underscore']
		},

		marionette: {
			exports: 'Backbone.Marionette',
			deps: ['backbone']
		}
	},

	deps: ['jquery', 'underscore']
});

require([
	'app',
	'backbone',
	'routers/index',
	'controllers/index'
], function (app, Backbone, Router, Controller) {
	'use strict';

	app.start();

	new Router({ controller: Controller });

	Backbone.history.start();
});
<commit_msg>removes un-used (and un-needed) shim for backbone.localStorage<commit_after>require.config({
	paths: {
		underscore: '../bower_components/underscore/underscore',
		backbone: '../bower_components/backbone/backbone',
		marionette: '../bower_components/backbone.marionette/lib/backbone.marionette',
		jquery: '../bower_components/jquery/jquery',
		localStorage: '../bower_components/backbone.localStorage/backbone.localStorage',
		tpl: 'lib/tpl'
	},

	shim: {
		underscore: {
			exports: '_'
		},

		backbone: {
			exports: 'Backbone',
			deps: ['jquery', 'underscore']
		},

		marionette: {
			exports: 'Backbone.Marionette',
			deps: ['backbone']
		}
	},

	deps: ['jquery', 'underscore']
});

require([
	'app',
	'backbone',
	'routers/index',
	'controllers/index'
], function (app, Backbone, Router, Controller) {
	'use strict';

	app.start();

	new Router({ controller: Controller });

	Backbone.history.start();
});
<|endoftext|>


<commit_before>/**
 * Functions for working with the automagic URI/Slug generation with multipleslug support.
 *
 * @mixin
 * @namespace Bolt.slug
 *
 * @param {Object} bolt - The Bolt module.
 * @param {Object} $ - jQuery.
 */
(function (bolt, $) {
    /**
     * Field configuration.
     *
     * @typedef {Object} FieldConf
     * @memberof Bolt.slug
     *
     * @property {string} bind - Always 'slug'.
     * @property {string|null} contentId - Content Id.
     * @property {boolean} isEmpty - Is not set?
     * @property {string} key - The field key
     * @property {string} slug - Content slug.
     * @property {Array} uses - Fields used to automatically generate a slug.
     */

    /**
     * Field data.
     *
     * @typedef {Object} FieldData
     * @memberof Bolt.slug
     *
     * @property {Object} group - Group container.
     * @property {Object} show - Slug display.
     * @property {Object} data - Data field.
     * @property {Object} lock - Lock button.
     */

    /**
     * Bolt.slug mixin container.
     *
     * @private
     * @type {Object}
     */
    var slug = {};

    /**
     * Bind slug field.
     *
     * @static
     * @function init
     * @memberof Bolt.slug
     *
     * @param {Object} fieldset
     * @param {FieldConf} fconf
     */
    slug.init = function (fieldset, fconf) {
        var field = {
                group: $(fieldset).find('.input-group'),
                show: $(fieldset).find('em'),
                data: $(fieldset).find('input'),
                lock: $(fieldset).find('button.lock')
            };

        field.lock.bind('click', function () {
            if (field.group.hasClass('locked')) {
                // "unlock" if it's currently empty, _or_ we've confirmed that we want to do so.
                if (fconf.isEmpty || confirm(Bolt.data('field.slug.message.unlock'))) {
                    field.group.removeClass('locked').addClass('unlocked');
                    makeUri(fconf.slug, fconf.contentId, fconf.uses, fconf.key, field, false);
                }
            } else {
                field.group.removeClass('unlocked').addClass('locked');
                stopMakeUri(fconf.key, fconf.uses);
            }
            this.blur();
        });

        $(fieldset).find('button.edit').bind('click', function () {
            var newslug = prompt(Bolt.data('field.slug.message.set'), field.data.val());

            if (newslug) {
                field.group.removeClass('unlocked').addClass('locked');
                stopMakeUri(fconf.key, fconf.uses);
                makeUriAjax(newslug, fconf.slug, fconf.contentId, fconf.key, field, false);
            }
            this.blur();
        });

        if (fconf.isEmpty) {
            field.lock.trigger('click');
        }
    };

    /**
     * Timeout.
     *
     * @private
     * @type {Array}
     * @memberof Bolt.slug
     */
    var timeout = [];

    /**
     * Make sure events are bound only once.
     *
     * @private
     * @type {boolean}
     * @memberof Bolt.slug
     */
    var isBound = false;

    /**
     * Get URI for slug from remote
     *
     * @private
     * @function makeUriAjax
     * @memberof Bolt.slug
     *
     * @param {string} text - New slug text.
     * @param {string} contenttypeSlug - Contenttype slug.
     * @param {string} id - Id.
     * @param {string} slugFieldId - Id of the slug field.
     * @param {FieldData} field - Field data.
     * @param {boolean} fullUri - Get the full URI?
     */
    function makeUriAjax(text, contenttypeSlug, id, slugFieldId, field, fullUri) {
        $.ajax({
            url: bolt.conf('paths.async') + 'makeuri',
            type: 'GET',
            data: {
                title: text,
                contenttypeslug: contenttypeSlug,
                id: id,
                slugfield: slugFieldId,
                fulluri: fullUri
            },
            success: function (uri) {
                field.data.val(uri);
                field.show.html(uri);
            },
            error: function () {
                console.log('failed to get an URI');
            }
        });
    }

    /**
     * make Uri from input
     *
     * @private
     * @function makeUri
     * @memberof Bolt.slug
     *
     * @param {string} contenttypeSlug - Contenttype slug.
     * @param {string} id - Id.
     * @param {Array} usesFields - Field used to automatically generate a slug.
     * @param {string} slugFieldId - Id of the slug field.
     * @param {FieldData} field - Field data.
     * @param {boolean} fullUri - Get the full URI?
     */
    function makeUri(contenttypeSlug, id, usesFields, slugFieldId, field, fullUri) {
        $.each(usesFields, function (i, bindField) {
            $('#' + bindField).on('propertychange.bolt input.bolt change.bolt', function () {
                var usesValue = [];

                $.each(usesFields, function (i, useField) {
                    var field = $('#' + useField);

                    if (field.is('select')) {
                        field.find('option:selected').each(function(i, option) {
                            if (option.text !== '') {
                                usesValue.push(option.text);
                            }
                        });
                    } else if (field.val()) {
                        usesValue.push(field.val());
                    }
                });

                clearTimeout(timeout[slugFieldId]);
                timeout[slugFieldId] = setTimeout(
                    function () {
                        makeUriAjax(usesValue.join(' '), contenttypeSlug, id, slugFieldId, field, fullUri);
                    },
                    200
                );
            }).trigger('change.bolt');
        });
    }

    /**
     * Stop making URI
     *
     * @private
     * @function stopMakeUri
     * @memberof Bolt.slug
     *
     * @param {string} slugFieldId - Id of the slug field.
     * @param {Array} usesFields - Field used to automatically generate a slug.
     */
    function stopMakeUri(slugFieldId, usesFields) {
        $.each(usesFields, function (i, name) {
            $('#' + name).unbind('propertychange.bolt input.bolt change.bolt');
        });
        clearTimeout(timeout[slugFieldId]);
    }

    // Apply mixin container
    bolt.slug = slug;

})(Bolt || {}, jQuery);
<commit_msg>Remove fulluri parameter as it's always false<commit_after>/**
 * Functions for working with the automagic URI/Slug generation with multipleslug support.
 *
 * @mixin
 * @namespace Bolt.slug
 *
 * @param {Object} bolt - The Bolt module.
 * @param {Object} $ - jQuery.
 */
(function (bolt, $) {
    /**
     * Field configuration.
     *
     * @typedef {Object} FieldConf
     * @memberof Bolt.slug
     *
     * @property {string} bind - Always 'slug'.
     * @property {string|null} contentId - Content Id.
     * @property {boolean} isEmpty - Is not set?
     * @property {string} key - The field key
     * @property {string} slug - Content slug.
     * @property {Array} uses - Fields used to automatically generate a slug.
     */

    /**
     * Field data.
     *
     * @typedef {Object} FieldData
     * @memberof Bolt.slug
     *
     * @property {Object} group - Group container.
     * @property {Object} show - Slug display.
     * @property {Object} data - Data field.
     * @property {Object} lock - Lock button.
     */

    /**
     * Bolt.slug mixin container.
     *
     * @private
     * @type {Object}
     */
    var slug = {};

    /**
     * Bind slug field.
     *
     * @static
     * @function init
     * @memberof Bolt.slug
     *
     * @param {Object} fieldset
     * @param {FieldConf} fconf
     */
    slug.init = function (fieldset, fconf) {
        var field = {
                group: $(fieldset).find('.input-group'),
                show: $(fieldset).find('em'),
                data: $(fieldset).find('input'),
                lock: $(fieldset).find('button.lock')
            };

        field.lock.bind('click', function () {
            if (field.group.hasClass('locked')) {
                // "unlock" if it's currently empty, _or_ we've confirmed that we want to do so.
                if (fconf.isEmpty || confirm(Bolt.data('field.slug.message.unlock'))) {
                    field.group.removeClass('locked').addClass('unlocked');
                    makeUri(fconf.slug, fconf.contentId, fconf.uses, fconf.key, field);
                }
            } else {
                field.group.removeClass('unlocked').addClass('locked');
                stopMakeUri(fconf.key, fconf.uses);
            }
            this.blur();
        });

        $(fieldset).find('button.edit').bind('click', function () {
            var newslug = prompt(Bolt.data('field.slug.message.set'), field.data.val());

            if (newslug) {
                field.group.removeClass('unlocked').addClass('locked');
                stopMakeUri(fconf.key, fconf.uses);
                makeUriAjax(newslug, fconf.slug, fconf.contentId, fconf.key, field);
            }
            this.blur();
        });

        if (fconf.isEmpty) {
            field.lock.trigger('click');
        }
    };

    /**
     * Timeout.
     *
     * @private
     * @type {Array}
     * @memberof Bolt.slug
     */
    var timeout = [];

    /**
     * Make sure events are bound only once.
     *
     * @private
     * @type {boolean}
     * @memberof Bolt.slug
     */
    var isBound = false;

    /**
     * Get URI for slug from remote
     *
     * @private
     * @function makeUriAjax
     * @memberof Bolt.slug
     *
     * @param {string} text - New slug text.
     * @param {string} contenttypeSlug - Contenttype slug.
     * @param {string} id - Id.
     * @param {string} slugFieldId - Id of the slug field.
     * @param {FieldData} field - Field data.
     */
    function makeUriAjax(text, contenttypeSlug, id, slugFieldId, field) {
        $.ajax({
            url: bolt.conf('paths.async') + 'makeuri',
            type: 'GET',
            data: {
                title: text,
                contenttypeslug: contenttypeSlug,
                id: id,
                slugfield: slugFieldId,
                fulluri: false
            },
            success: function (uri) {
                field.data.val(uri);
                field.show.html(uri);
            },
            error: function () {
                console.log('failed to get an URI');
            }
        });
    }

    /**
     * make Uri from input
     *
     * @private
     * @function makeUri
     * @memberof Bolt.slug
     *
     * @param {string} contenttypeSlug - Contenttype slug.
     * @param {string} id - Id.
     * @param {Array} usesFields - Field used to automatically generate a slug.
     * @param {string} slugFieldId - Id of the slug field.
     * @param {FieldData} field - Field data.
     */
    function makeUri(contenttypeSlug, id, usesFields, slugFieldId, field) {
        $.each(usesFields, function (i, bindField) {
            $('#' + bindField).on('propertychange.bolt input.bolt change.bolt', function () {
                var usesValue = [];

                $.each(usesFields, function (i, useField) {
                    var field = $('#' + useField);

                    if (field.is('select')) {
                        field.find('option:selected').each(function(i, option) {
                            if (option.text !== '') {
                                usesValue.push(option.text);
                            }
                        });
                    } else if (field.val()) {
                        usesValue.push(field.val());
                    }
                });

                clearTimeout(timeout[slugFieldId]);
                timeout[slugFieldId] = setTimeout(
                    function () {
                        makeUriAjax(usesValue.join(' '), contenttypeSlug, id, slugFieldId, field);
                    },
                    200
                );
            }).trigger('change.bolt');
        });
    }

    /**
     * Stop making URI
     *
     * @private
     * @function stopMakeUri
     * @memberof Bolt.slug
     *
     * @param {string} slugFieldId - Id of the slug field.
     * @param {Array} usesFields - Field used to automatically generate a slug.
     */
    function stopMakeUri(slugFieldId, usesFields) {
        $.each(usesFields, function (i, name) {
            $('#' + name).unbind('propertychange.bolt input.bolt change.bolt');
        });
        clearTimeout(timeout[slugFieldId]);
    }

    // Apply mixin container
    bolt.slug = slug;

})(Bolt || {}, jQuery);
<|endoftext|>


<commit_before>function parseUrl(url) {
    var parser = document.createElement('a');
    parser.href = url;
    return getQueryParams(parser.search);
}

function getQueryParams(qs) {
    qs = qs.split('+').join(' ');
    var params = {},
        tokens,
        re = /[?&]?([^=]+)=([^&]*)/g;
    while (tokens = re.exec(qs)) {
        params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }
    return params;
}

function isTrue(val) {
    return val === '1' || val === 1 || val === true
        || ('' + val).toLowerCase() === 'true';
}

function createRosUrl(params) {
    if (params['rosbridge_secure'] === undefined) {
        // Set the default value
        var protocol = 'wss://';
    }
    else {
        var protocol = (isTrue(params['rosbridge_secure']) ? 'wss://' : 'ws://');
    }
    return protocol
        + (params['rosbridge_host'] || 'localhost' ) + ':'
        + (params['rosbridge_port'] || '9090');
}

function loadGETParams(url, callback) {
    var params = parseUrl(url);
    if (params['ros_instance_name'] !== undefined) {
      console.log("Read url", url);
      callback(params);
      return;
    }
    else {
        // woops, looks like google maps
        chrome.history.search({text: '', maxResults: 10}, function(histItems) {
            for (var i = 0; i < histItems.length; i++) {
                var histItem = histItems[i];
                if (histItem.url && histItem.url.indexOf('ros_instance_name') >= 0) {
                    console.log("Red from history", histItem.url);
                    var params = parseUrl(histItem.url);
                    callback(params);
                    return;
                }
            }
            console.log('ERROR: Failed to load ros_instance_name and rosbridge parameters');
        });
    }
}

function State() {
    this.flags = {
      rosReady: false,
      urlParsed: false,
      domLoadedMsg: false,
      domLoadedEvnt: false,
      customReadyMsg: false
    };

    this.waiters = {};
}

State.prototype.setFlag = function(key) {
    this.flags[key] = true;
    this.callWaiters(key);
};

State.prototype.callWaiters = function(flag) {
  var changes = false;
  for(var wk in this.waiters) {
    if (this.waiters.hasOwnProperty(wk)) {
      changes = changes || this.waiters[wk](this.flags, flag);
    }
  }

  if (changes) {
    this.callWaiters(null);
  }
};

State.prototype.addWaiter = function(key, waiter) {
    if (this.waiters[key] === undefined) {
        this.waiters[key] = waiter;
    }
};

function WindowReadyExt() {
    this.rosUrl = null;
    this.ros_window_name = null;

    this.readyTopic = null;
    this.ros = null;
    this.sentIds = {};

    this.state = new State();

    var extension = this;
    this.state.addWaiter('initRos', function(flags) {
        // Initialize ros, after we've got url parameters
        if (flags.urlParsed && !flags.rosReady) {
            extension.initRos();
        }
    });

    // See getSendMsgwaiter
    this.domLoadedWaiter = function(flags) {
        // Everything is ready
        if (flags.rosReady && flags.urlParsed
            // And one we auqired dom loaded one way or another
            && (flags.domLoadedMsg || flags.domLoadedEvnt)) {

            if(!extension.use_app_event) {
                extension.sendMsg();
                if (extension.chromeCallback) {
                    extension.chromeCallback({ack: true});
                }
            }
        }
    };

    this.attachListeners();
}

WindowReadyExt.prototype.initRos = function() {
    if (this.readyTopic) {
        return;
    }

    var extension = this;

    this.ros = new ROSLIB.Ros();

    this.ros.on('error', function(error) {
        extension.onRosError.apply(extension, [error]);
    });

    this.ros.on('connection', function() {
        console.log('Connection made!');

        extension.readyTopic = new ROSLIB.Topic({
            ros: extension.ros,
            name: '/director/window/ready',
            messageType: 'std_msgs/String',
            throttle_rate: 33
        });
        this.readyTopic.advertise();
        console.log("Advertised on the topic /director/window/ready");

        extension.state.setFlag.apply(extension.state, ['rosReady']);
    });

    console.log("Trying to connect to ROS with URL: " + this.rosUrl);
    this.ros.connect(this.rosUrl);

    this.ros.callOnConnection();
};

WindowReadyExt.prototype.onRosError = function(error) {
    console.log(error);
    // If you want to retry connection to ros
    // do it here. Change the url, and call
    // this.ros.connect(this.rosUrl);
    // callbacks already binded
};

WindowReadyExt.prototype.sendMsg = function() {
    if(this.sentIds[this.ros_window_name]) {
      return;
    }

    this.sentIds[this.ros_window_name] = true;

    this.readyTopic.publish({'data': this.ros_window_name});
    console.log("Sent " + this.ros_window_name);
    console.log("Repeating window ready msg once a second");

    var self = this;
    this.repeatInterval = setInterval(function() {
        self.readyTopic.publish({'data': self.ros_window_name});
    }, 1000);
};

WindowReadyExt.prototype.attachListeners = function() {
    var extension = this;

    // Listen for DOM_LOADED message from host message
    // if page was loaded before extension.
    chrome.runtime.onMessage.addListener(
        function(msg, sender, sendResponse) {
            if (msg.type == "DOM_LOADED") {
                return extension.domLoadedMsg.apply(extension, [sender, sendResponse]);
            }
            if (msg.type == "DIRECTOR_WINDOW_READY") {
                return extension.directorWindowMsg.apply(extension, [sender, sendResponse]);
            }
        }
    );

    chrome.webNavigation.onDOMContentLoaded.addListener(function(data) {
        if (data && data.url) {
            loadGETParams(data.url, function(params) {
                extension.applyUrlParams.apply(extension, [params]);
                extension.domLoadedEvnt.apply(extension, []);
            });
        }
    });
};

// * Parse and set ros url
// * Initialize ROS
// * Set ros_instance_name
WindowReadyExt.prototype.applyUrlParams = function(params) {
    this.rosUrl = createRosUrl(params);
    // Used !! to explicitly convert to boolean
    this.use_app_event = !!params['use_app_event'];

    var instanceName = params['ros_instance_name'];
    if (instanceName !== undefined) {
        this.ros_window_name = instanceName;
        console.log("Acuired ros_window_name", this.ros_window_name);
        this.state.setFlag('urlParsed');
    }
};

// Dom loaded system message
WindowReadyExt.prototype.domLoadedEvnt = function() {
    this.state.addWaiter('sendMsg', this.domLoadedWaiter);
    this.state.setFlag('domLoadedEvnt');
};

// Custom message recieved
WindowReadyExt.prototype.directorWindowMsg = function(sender, sendResponse) {
    console.log('Got DIRECTOR_WINDOW_READY message from content');

    var extension = this;
    this.state.addWaiter('directorWindowMsg', function(flags) {
        // Initialize ros, after we've got url parameters
        if (flags.urlParsed && flags.rosReady && flags.customReadyMsg) {
            if (extension.use_app_event) {
                extension.sendMsg();
            }
            sendResponse({ack: true});
        }
    });
    this.state.setFlag('customReadyMsg');
    // Return true for chrome, to deal with sendResponse asychronosly
    return true;
};

// Dom loaded message from hosted page
WindowReadyExt.prototype.domLoadedMsg = function(sender, sendResponse) {
    var extension = this;
    this.chromeCallback = sendResponse;
    // Add actual callback which will send a message
    this.state.addWaiter('sendMsg', this.domLoadedWaiter);

    // Get url parameters from
    if(sender.url) {
        loadGETParams(sender.url, function(params){
            extension.applyUrlParams.apply(extension, [params]);
            extension.state.setFlag('domLoadedMsg');
        });
    }
    else {
        chrome.tabs.query({active: true}, function(tabs) {
            if (tabs.length == 0) {
                console.log("Can't aquire url, active tabs are empty");
                return false;
            }
            loadGETParams(tabs[0].url, function(params){
                extension.applyUrlParams(params);
                extension.state.setFlag('domLoadedMsg');
            });
        });
    }

    // Needed to use sendResponse callback asynchronusly
    return true;
};

var INSTANCE = new WindowReadyExt();
<commit_msg>Remove infinite cycle in ros_window_ready extension logging<commit_after>function parseUrl(url) {
    var parser = document.createElement('a');
    parser.href = url;
    return getQueryParams(parser.search);
}

function getQueryParams(qs) {
    qs = qs.split('+').join(' ');
    var params = {},
        tokens,
        re = /[?&]?([^=]+)=([^&]*)/g;
    while (tokens = re.exec(qs)) {
        params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }
    return params;
}

function isTrue(val) {
    return val === '1' || val === 1 || val === true
        || ('' + val).toLowerCase() === 'true';
}

function createRosUrl(params) {
    if (params['rosbridge_secure'] === undefined) {
        // Set the default value
        var protocol = 'wss://';
    }
    else {
        var protocol = (isTrue(params['rosbridge_secure']) ? 'wss://' : 'ws://');
    }
    return protocol
        + (params['rosbridge_host'] || 'localhost' ) + ':'
        + (params['rosbridge_port'] || '9090');
}

function loadGETParams(url, callback) {
    var params = parseUrl(url);
    if (params['ros_instance_name'] !== undefined) {
      callback(params);
      return;
    }
    else {
        // woops, looks like google maps
        chrome.history.search({text: '', maxResults: 10}, function(histItems) {
            for (var i = 0; i < histItems.length; i++) {
                var histItem = histItems[i];
                if (histItem.url && histItem.url.indexOf('ros_instance_name') >= 0) {
                    console.log("Red from history", histItem.url);
                    var params = parseUrl(histItem.url);
                    callback(params);
                    return;
                }
            }
            console.log('ERROR: Failed to load ros_instance_name and rosbridge parameters');
        });
    }
}

function State() {
    this.flags = {
      rosReady: false,
      urlParsed: false,
      domLoadedMsg: false,
      domLoadedEvnt: false,
      customReadyMsg: false
    };

    this.waiters = {};
}

State.prototype.setFlag = function(key) {
    this.flags[key] = true;
    this.callWaiters(key);
};

State.prototype.callWaiters = function(flag) {
  var changes = false;
  for(var wk in this.waiters) {
    if (this.waiters.hasOwnProperty(wk)) {
      changes = changes || this.waiters[wk](this.flags, flag);
    }
  }

  if (changes) {
    this.callWaiters(null);
  }
};

State.prototype.addWaiter = function(key, waiter) {
    if (this.waiters[key] === undefined) {
        this.waiters[key] = waiter;
    }
};

function WindowReadyExt() {
    this.rosUrl = null;
    this.ros_window_name = null;

    this.readyTopic = null;
    this.ros = null;
    this.sentIds = {};

    this.state = new State();

    var extension = this;
    this.state.addWaiter('initRos', function(flags) {
        // Initialize ros, after we've got url parameters
        if (flags.urlParsed && !flags.rosReady) {
            extension.initRos();
        }
    });

    // See getSendMsgwaiter
    this.domLoadedWaiter = function(flags) {
        // Everything is ready
        if (flags.rosReady && flags.urlParsed
            // And one we auqired dom loaded one way or another
            && (flags.domLoadedMsg || flags.domLoadedEvnt)) {

            if(!extension.use_app_event) {
                extension.sendMsg();
            }
            // Send answer to hosted page anyway
            if (extension.chromeCallback) {
                extension.chromeCallback({ack: true});
            }
        }
    };

    this.attachListeners();
}

WindowReadyExt.prototype.initRos = function() {
    if (this.readyTopic) {
        return;
    }

    var extension = this;

    this.ros = new ROSLIB.Ros();

    this.ros.on('error', function(error) {
        extension.onRosError.apply(extension, [error]);
    });

    this.ros.on('connection', function() {
        console.log('Connection made!');

        extension.readyTopic = new ROSLIB.Topic({
            ros: extension.ros,
            name: '/director/window/ready',
            messageType: 'std_msgs/String',
            throttle_rate: 33
        });
        this.readyTopic.advertise();
        console.log("Advertised on the topic /director/window/ready");

        extension.state.setFlag.apply(extension.state, ['rosReady']);
    });

    console.log("Trying to connect to ROS with URL: " + this.rosUrl);
    this.ros.connect(this.rosUrl);

    this.ros.callOnConnection();
};

WindowReadyExt.prototype.onRosError = function(error) {
    console.log(error);
    // If you want to retry connection to ros
    // do it here. Change the url, and call
    // this.ros.connect(this.rosUrl);
    // callbacks already binded
};

WindowReadyExt.prototype.sendMsg = function() {
    if(this.sentIds[this.ros_window_name]) {
      return;
    }

    this.sentIds[this.ros_window_name] = true;

    this.readyTopic.publish({'data': this.ros_window_name});
    console.log("Sent " + this.ros_window_name);
    console.log("Repeating window ready msg once a second");

    var self = this;
    this.repeatInterval = setInterval(function() {
        self.readyTopic.publish({'data': self.ros_window_name});
    }, 1000);
};

WindowReadyExt.prototype.attachListeners = function() {
    var extension = this;

    // Listen for DOM_LOADED message from host message
    // if page was loaded before extension.
    chrome.runtime.onMessage.addListener(
        function(msg, sender, sendResponse) {
            if (msg.type == "DOM_LOADED") {
                return extension.domLoadedMsg.apply(extension, [sender, sendResponse]);
            }
            if (msg.type == "DIRECTOR_WINDOW_READY") {
                return extension.directorWindowMsg.apply(extension, [sender, sendResponse]);
            }
        }
    );

    chrome.webNavigation.onDOMContentLoaded.addListener(function(data) {
        if (data && data.url) {
            loadGETParams(data.url, function(params) {
                extension.applyUrlParams.apply(extension, [params]);
                extension.domLoadedEvnt.apply(extension, []);
            });
        }
    });
};

// * Parse and set ros url
// * Initialize ROS
// * Set ros_instance_name
WindowReadyExt.prototype.applyUrlParams = function(params) {
    this.rosUrl = createRosUrl(params);
    // Used !! to explicitly convert to boolean
    this.use_app_event = !!params['use_app_event'];

    var instanceName = params['ros_instance_name'];
    if (instanceName !== undefined) {
        this.ros_window_name = instanceName;
        this.state.setFlag('urlParsed');
    }
};

// Dom loaded system message
WindowReadyExt.prototype.domLoadedEvnt = function() {
    this.state.addWaiter('sendMsg', this.domLoadedWaiter);
    this.state.setFlag('domLoadedEvnt');
};

// Custom message recieved
WindowReadyExt.prototype.directorWindowMsg = function(sender, sendResponse) {
    console.log('Got DIRECTOR_WINDOW_READY message from content');

    var extension = this;
    this.state.addWaiter('directorWindowMsg', function(flags) {
        // Initialize ros, after we've got url parameters
        if (flags.urlParsed && flags.rosReady && flags.customReadyMsg) {
            if (extension.use_app_event) {
                extension.sendMsg();
            }
            sendResponse({ack: true});
        }
    });
    this.state.setFlag('customReadyMsg');
    // Return true for chrome, to deal with sendResponse asychronosly
    return true;
};

// Dom loaded message from hosted page
WindowReadyExt.prototype.domLoadedMsg = function(sender, sendResponse) {
    var extension = this;
    this.chromeCallback = sendResponse;
    // Add actual callback which will send a message
    this.state.addWaiter('sendMsg', this.domLoadedWaiter);

    // Get url parameters from
    if(sender.url) {
        loadGETParams(sender.url, function(params){
            extension.applyUrlParams.apply(extension, [params]);
            extension.state.setFlag('domLoadedMsg');
        });
    }
    else {
        chrome.tabs.query({active: true}, function(tabs) {
            if (tabs.length == 0) {
                console.log("Can't aquire url, active tabs are empty");
                return false;
            }
            loadGETParams(tabs[0].url, function(params){
                extension.applyUrlParams(params);
                extension.state.setFlag('domLoadedMsg');
            });
        });
    }

    // Needed to use sendResponse callback asynchronusly
    return true;
};

var INSTANCE = new WindowReadyExt();
<|endoftext|>


<commit_before>
  /**
   *  Controller to show correct dialog to finally get share dialog.
   *
   *  - If the visualization is the type table -> Create visualization
   *  - If the visualization derived is private -> Make visualization private
   *  - If the visualization derived is private -> Turn private tables into public
   *  - Show share window
   *
   *  var controller = new cdb.admin.ShareController({
   *    model:  vis_model,
   *    user:   user_model,
   *    config: config_params
   *  });
   */

  cdb.admin.ShareController = cdb.core.View.extend({

    _TEXTS: {
      create_visualization: {
        msg:        _t('If you want to share your map you need to create a visualization.')
      },
      next_button:  _t('Check tables')
    },

    // Add to the stack then number of actions we need to do
    initialize: function() {
      this.user = this.options.user;
      this.config = this.options.config;
      this.stack = [];

      this.any_private_table = this.model.related_tables && this.model.related_tables.filter(function(table) {
        return table.get("privacy").toLowerCase() == "private"
      }).length > 0;

      // Generate stack
      this._generateStack();

      // Start
      this._nextStep();
    },

    _generateStack: function() {
      // If the visualization is a table type
      if (!this.model.isVisualization()) {
        this.stack.push({
          class: 'CreateVizDialog',
          step: 'createVisualization',
          opts: {
            model: this.model,
            msg: this._TEXTS.create_visualization.msg
          },
          center: false,
          callback: '_changeToVis'
        });
      }

      // Check if the visualization is private
      if (this.model.isVisualization()) {

// TODO: @jamon set proper code, temporally bypass to test named maps
/*
        if (this.any_private_table) {
          // If there is any private table
          // show the private tables dialog
          // We count with the model is PRIVATE ALWAYS
          this.stack.push({
            class: 'SharePrivateTablesDialog',
            step: 'makeTablesAndVizPublic',
            opts: {
              model: this.model,
              ok_next: _t('Make viz public and share')
            },
            center: false,
            callback: '_makeVisPublic'
          });
        } else if (this.model.get('privacy') == "PRIVATE") {
          // If not, just show the viz private dialog
          this.stack.push({
            class: 'SharePrivateVisDialog',
            step: 'makeVisualizationPublic',
            opts: {
              model: this.model,
              next_button: this.any_private_table ? this._TEXTS.next_button : null
            },
            center: false
          });
        }
*/
        //this.model.save({
          //privacy: 'PUBLIC'
        //})

      }

      // Add share dialog if it is visualization
      if (this.model.isVisualization()) {
        this.stack.push({
          class: 'ShareDialog',
          step: 'showShareDialog',
          opts: {
            vis:    this.model,
            user:   this.user,
            config: this.config
          },
          center: true
        });
      }
    },

    _createDialog: function() {
      var self = this;
      var step = self.stack.shift();

      var dlg = new cdb.admin[step.class](step.opts);

      dlg.cancel = function() { self._clean() }
      dlg.ok = function(r) {
        step.callback && self[step.callback](r);
        self._nextStep();
      }

      dlg.appendToBody().open({ center: step.center });
      this.addView(dlg);
    },

    _makeVisPublic: function() {
      this.model.save({
        privacy: 'PUBLIC'
      })
    },

    _changeToVis: function(vis) {
      // Get scenario param (table or map)
      var last_route = window.table_router.history.length > 0 && _.last(window.table_router.history).split('/');
      // Create url
      var url = "/viz/" + vis.get("id") + "/" + ( last_route[2] || 'table' );
      // Navigate
      window.table_router.navigate(url, { trigger: false });
      window.table_router.addToHistory();
    },

    // Do next step until the end
    _nextStep: function() {
      if (this.stack.length > 0) {
        this._createDialog();
      } else {
        this._clean();
      }
    },

    // hack to prevent remove the dialog inmediatelly
    _clean: function() {
      var self = this;
      setTimeout(function() {
        self.clean()
      }, 1000);
    },

    // Clean clean cleaaaaaaaaaaan!
    clean: function() {
      this.stack = [];
      cdb.core.View.prototype.clean.call(this);
    }

  });
<commit_msg>remove old commented code<commit_after>
  /**
   *  Controller to show correct dialog to finally get share dialog.
   *
   *  - If the visualization is the type table -> Create visualization
   *  - If the visualization derived is private -> Make visualization private
   *  - If the visualization derived is private -> Turn private tables into public
   *  - Show share window
   *
   *  var controller = new cdb.admin.ShareController({
   *    model:  vis_model,
   *    user:   user_model,
   *    config: config_params
   *  });
   */

  cdb.admin.ShareController = cdb.core.View.extend({

    _TEXTS: {
      create_visualization: {
        msg:        _t('If you want to share your map you need to create a visualization.')
      },
      next_button:  _t('Check tables')
    },

    // Add to the stack then number of actions we need to do
    initialize: function() {
      this.user = this.options.user;
      this.config = this.options.config;
      this.stack = [];

      this.any_private_table = this.model.related_tables && this.model.related_tables.filter(function(table) {
        return table.get("privacy").toLowerCase() == "private"
      }).length > 0;

      // Generate stack
      this._generateStack();

      // Start
      this._nextStep();
    },

    _generateStack: function() {
      // If the visualization is a table type
      if (!this.model.isVisualization()) {
        this.stack.push({
          class: 'CreateVizDialog',
          step: 'createVisualization',
          opts: {
            model: this.model,
            msg: this._TEXTS.create_visualization.msg
          },
          center: false,
          callback: '_changeToVis'
        });
      }

      // Add share dialog if it is visualization
      if (this.model.isVisualization()) {
        this.stack.push({
          class: 'ShareDialog',
          step: 'showShareDialog',
          opts: {
            vis:    this.model,
            user:   this.user,
            config: this.config
          },
          center: true
        });
      }
    },

    _createDialog: function() {
      var self = this;
      var step = self.stack.shift();

      var dlg = new cdb.admin[step.class](step.opts);

      dlg.cancel = function() { self._clean() }
      dlg.ok = function(r) {
        step.callback && self[step.callback](r);
        self._nextStep();
      }

      dlg.appendToBody().open({ center: step.center });
      this.addView(dlg);
    },

    _makeVisPublic: function() {
      this.model.save({
        privacy: 'PUBLIC'
      })
    },

    _changeToVis: function(vis) {
      // Get scenario param (table or map)
      var last_route = window.table_router.history.length > 0 && _.last(window.table_router.history).split('/');
      // Create url
      var url = "/viz/" + vis.get("id") + "/" + ( last_route[2] || 'table' );
      // Navigate
      window.table_router.navigate(url, { trigger: false });
      window.table_router.addToHistory();
    },

    // Do next step until the end
    _nextStep: function() {
      if (this.stack.length > 0) {
        this._createDialog();
      } else {
        this._clean();
      }
    },

    // hack to prevent remove the dialog inmediatelly
    _clean: function() {
      var self = this;
      setTimeout(function() {
        self.clean()
      }, 1000);
    },

    // Clean clean cleaaaaaaaaaaan!
    clean: function() {
      this.stack = [];
      cdb.core.View.prototype.clean.call(this);
    }

  });
<|endoftext|>


<commit_before>
describe("cdb.admin.Filters", function() {

  var filterView, table, filter;
  beforeEach(function() {

    table = TestUtil.createTable('tst');

    filterView = new cdb.admin.mod.Filters({
      table: table,
      dataLayer: new cdb.admin.CartoDBLayer({
        name: 'test'
      }),
      repeatInterval: -1
    });

    var m = new cdb.admin.models.Filter({
      column: 'test',
      table: table,
      lower: 1,
      upper: 10,
      column_type: 'number'
    });
    filter = m;

  });

  it("should manage models filter view", function() {
    filterView.render();
    filterView.filters.add(filter);
    expect(filterView.$('li').length).toEqual(1);
    filter.destroy();
    expect(filterView.$('li').length).toEqual(0);
  });

  it("should serialize filters data to layer", function() {
    filterView.render();
    filterView.filters.add(filter);
    filter.set('lower', 0)
    var f = filterView.options.dataLayer.get('filters');
    expect(f).toEqual([filter.toJSON()])

  });

  describe('cdb.admin.mod.Filter', function() {
    var filter, model;

    beforeEach(function() {
      model = new cdb.admin.models.Filter({
        column: 'test',
        table: table
      });
      view = new cdb.admin.mod.Filter({
        model: model
      });
    });

    it("should render", function() {
      view.render();
      expect(view.$('.legend').html()).toEqual('test:');
    });

    it("should be removed", function() {
      spyOn(model, 'destroy');
      view.render();
      view.$('a.remove').click();
      expect(model.destroy).toHaveBeenCalled();
    });

    it("should update the dropdowns", function() {

      spyOn(filterView.columnSelector, "updateData");
      spyOn(filterView.innerColumnSelector, "updateData");

      table.set({ schema:[ ['test',  'number'], ['test2', 'number'] ] });

      expect(filterView.columnSelector.updateData).toHaveBeenCalled();
      expect(filterView.innerColumnSelector.updateData).toHaveBeenCalled();

    });

    //it("should update hist", function() {

      //hist = [0,1,2,3,4,5,5,6,6,7,8,8];
      //view.model.set("hist", hist);

      //console.log(this.model.get("lower"));

      //view.render();
      //view._renderHist();

      //var bounds = {};

      //bounds.lower = 2;
      //bounds.upper = 40;

      //view.model._changeHist(hist);

      //console.log(view.$el.find(".hist").html());

      //expect(view.$('.range').html()).toEqual('2 - 40');
      //expect(view.$el.find('svg').length).toEqual(1);
      //expect(view.$('.bar').length).toEqual(hist.length);

    //});

  });

  describe('cdb.admin.mod.SelectorFilter', function() {
    var filter, model;

    beforeEach(function() {

      model = new cdb.admin.models.FilterDiscrete({
        column: 'test',
        table: table,
        column_type: 'string'
      });

      view = new cdb.admin.mod.SelectorFilter({
        model: model
      });

    });

    it("should render items", function() {

      model._updateHist({ rows: [
        { bucket: 'test', value: 10},
        { bucket: 'test2', value: 20}
      ]});

      view.render();

      expect(view.$('ul.items li').length).toEqual(2);

    });

    it("should pass the reached_limit flag to the model", function() {

      model._updateHist({ reached_limit: false, rows: [
        { bucket: 'test',  value: 10},
        { bucket: 'test2', value: 20}
      ]});

      expect(model.get("reached_limit")).toEqual(false);

    });

    it("should disable/enable items", function() {
      model._updateHist({ rows: [
        { bucket: 'test', value: 10},
        { bucket: 'test2', value: 20}
      ]});

      view.render();

      view.$('ul.items li')[0].click();

      expect(model.items.at(0).get('selected')).toEqual(false);
      expect(model.items.at(1).get('selected')).toEqual(true);
      expect($(view.$('ul.items li')[0]).hasClass('selected')).toEqual(false);
      expect($(view.$('ul.items li')[1]).hasClass('selected')).toEqual(true);

      view.$('ul.items li')[0].click();

      expect(model.items.at(0).get('selected')).toEqual(true);
      expect(model.items.at(1).get('selected')).toEqual(true);

      expect($(view.$('ul.items li')[0]).hasClass('selected')).toEqual(true);
      expect($(view.$('ul.items li')[1]).hasClass('selected')).toEqual(true);
    });

  });

});
<commit_msg>filter module tests fixed<commit_after>
describe("cdb.admin.Filters", function() {

  var filterView, table, filter;
  beforeEach(function() {

    table = TestUtil.createTable('tst');
    dataLayer = new cdb.admin.CartoDBLayer({ name: 'test' });
    dataLayer.sync = function() {};
    var sqlView = new cdb.admin.SQLViewData();
    dataLayer.bindSQLView(sqlView);

    filterView = new cdb.admin.mod.Filters({
      table: table,
      dataLayer: dataLayer,
      repeatInterval: -1
    });

    var m = new cdb.admin.models.Filter({
      column: 'test',
      table: table,
      lower: 1,
      upper: 10,
      column_type: 'number'
    });
    filter = m;

  });

  it("should manage models filter view", function() {
    filterView.render();
    filterView.filters.add(filter);
    expect(filterView.$('li').length).toEqual(1);
    filter.destroy();
    expect(filterView.$('li').length).toEqual(0);
  });

  it("should serialize filters data to layer", function() {
    filterView.render();
    filterView.filters.add(filter);
    filter.set('lower', 0)
    var f = filterView.options.dataLayer.get('filters');
    expect(f).toEqual([filter.toJSON()])

  });

  describe('cdb.admin.mod.Filter', function() {
    var filter, model;

    beforeEach(function() {
      model = new cdb.admin.models.Filter({
        column: 'test',
        table: table
      });
      view = new cdb.admin.mod.Filter({
        model: model
      });
    });

    it("should render", function() {
      view.render();
      expect(view.$('.legend').html()).toEqual('test:');
    });

    it("should be removed", function() {
      spyOn(model, 'destroy');
      view.render();
      view.$('a.remove').click();
      expect(model.destroy).toHaveBeenCalled();
    });

    it("should update the dropdowns", function() {

      spyOn(filterView.columnSelector, "updateData");
      spyOn(filterView.innerColumnSelector, "updateData");

      table.set({ schema:[ ['test',  'number'], ['test2', 'number'] ] });

      expect(filterView.columnSelector.updateData).toHaveBeenCalled();
      expect(filterView.innerColumnSelector.updateData).toHaveBeenCalled();

    });

    //it("should update hist", function() {

      //hist = [0,1,2,3,4,5,5,6,6,7,8,8];
      //view.model.set("hist", hist);

      //console.log(this.model.get("lower"));

      //view.render();
      //view._renderHist();

      //var bounds = {};

      //bounds.lower = 2;
      //bounds.upper = 40;

      //view.model._changeHist(hist);

      //console.log(view.$el.find(".hist").html());

      //expect(view.$('.range').html()).toEqual('2 - 40');
      //expect(view.$el.find('svg').length).toEqual(1);
      //expect(view.$('.bar').length).toEqual(hist.length);

    //});

  });

  describe('cdb.admin.mod.SelectorFilter', function() {
    var filter, model;

    beforeEach(function() {

      model = new cdb.admin.models.FilterDiscrete({
        column: 'test',
        table: table,
        column_type: 'string'
      });

      view = new cdb.admin.mod.SelectorFilter({
        model: model
      });

    });

    it("should render items", function() {

      model._updateHist({ rows: [
        { bucket: 'test', value: 10},
        { bucket: 'test2', value: 20}
      ]});

      view.render();

      expect(view.$('ul.items li').length).toEqual(2);

    });

    it("should pass the reached_limit flag to the model", function() {

      model._updateHist({ reached_limit: false, rows: [
        { bucket: 'test',  value: 10},
        { bucket: 'test2', value: 20}
      ]});

      expect(model.get("reached_limit")).toEqual(false);

    });

    it("should disable/enable items", function() {
      model._updateHist({ rows: [
        { bucket: 'test', value: 10},
        { bucket: 'test2', value: 20}
      ]});

      view.render();

      view.$('ul.items li')[0].click();

      expect(model.items.at(0).get('selected')).toEqual(false);
      expect(model.items.at(1).get('selected')).toEqual(true);
      expect($(view.$('ul.items li')[0]).hasClass('selected')).toEqual(false);
      expect($(view.$('ul.items li')[1]).hasClass('selected')).toEqual(true);

      view.$('ul.items li')[0].click();

      expect(model.items.at(0).get('selected')).toEqual(true);
      expect(model.items.at(1).get('selected')).toEqual(true);

      expect($(view.$('ul.items li')[0]).hasClass('selected')).toEqual(true);
      expect($(view.$('ul.items li')[1]).hasClass('selected')).toEqual(true);
    });

  });

});
<|endoftext|>


<commit_before>(function () {
    'use strict';

    angular
        .module('atlas')
        .factory('printReducers', printReducersFactory);

    printReducersFactory.$inject = ['ACTIONS'];

    function printReducersFactory (ACTIONS) {
        var reducers = {};

        reducers[ACTIONS.SHOW_PRINT.id] = showPrintReducer;
        reducers[ACTIONS.HIDE_PRINT.id] = hidePrintReducer;

        return reducers;

        /**
         * @param {Object} oldState
         *
         * @returns {Object} newState
         */
        function showPrintReducer (oldState) {
            var newState = angular.copy(oldState);

            newState.atlas.isPrintMode = true;

            return newState;
        }

        /**
         * @param {Object} oldState
         *
         * @returns {Object} newState
         */
        function hidePrintReducer (oldState) {
            var newState = angular.copy(oldState);

            newState.atlas.isPrintMode = false;

            return newState;
        }
    }
})();

<commit_msg>added support for going to print page tg-2818<commit_after>(function () {
    'use strict';

    angular
        .module('atlas')
        .factory('printReducers', printReducersFactory);

    printReducersFactory.$inject = ['ACTIONS'];

    function printReducersFactory (ACTIONS) {
        var reducers = {};

        reducers[ACTIONS.SHOW_PRINT.id] = showPrintReducer;
        reducers[ACTIONS.HIDE_PRINT.id] = hidePrintReducer;

        return reducers;

        /**
         * @param {Object} oldState
         *
         * @returns {Object} newState
         */
        function showPrintReducer (oldState) {
            var newState = angular.copy(oldState);

            newState.atlas.isPrintMode = true;
            newState.map.drawingMode = 'none';

            return newState;
        }

        /**
         * @param {Object} oldState
         *
         * @returns {Object} newState
         */
        function hidePrintReducer (oldState) {
            var newState = angular.copy(oldState);

            newState.atlas.isPrintMode = false;
            newState.map.drawingMode = 'none';

            return newState;
        }
    }
})();

<|endoftext|>


<commit_before>/* USE
- all characters should extend from entityPrefab constructor
- all characters will share qualities defined in entityPrefab
*/

/* todo
- define collision here?
*/
// todo: weapon prefab
// todo: health bar
// todo: activity feed
// todo: set death property on living entity
// todo; displayHP function that shows numeric value upon hp change, different color for heal and damage

export default class entityPrefab extends Phaser.Sprite {
  constructor(game, name, position, properties) {
    /* property considerations:
      sprite - player class, monster npc type, friendly npc type,
      group - necessary?,
    */

    /* frames considerations:
      at higher level class that extends from prefab should have a this.frames property
      which is an object that stores multiple key value pairs where the key is animation type and value represents the frames array
      frames object - {'animationTypeOne': [frames], 'animationTypeTwo': [frames]}
    */
    super(game, position.x, position.y, properties.spriteKey, properties.initialFrame)

    // this.gameState = game
    // may not need this
    this.name = name
    this.initialFrame = properties.initalFrame
    this.attackTarget = null

    if (properties.group) {
      this.gameState.groups[properties.group].children.push(this)
      // gameState has groups object that stores all group types
    }

    game.add.existing(this)
    // adds current prefab to the gameState

    game.physics.p2.enable(this)

    game.prefabs[name] = this
    // don't need this?
    // gameState has prefabs object that allows access to current prefab sprite?
  }

  // phaser quest approach
  setAnimationFrames() {
    // add animations for 'idle' move' 'death' 'attack' to the sprite object entity
    // if playable character, the animation should be set to weapon as well
    const frames = this.frames

    // let deathFrames
    // if (frames.hasOwnProperty('death')) {
    //   deathFrames = Phaser.Animations.generateFrameNames(`${this.name}-death`, frames[death][0], frames[death][1])
    // } else {
    //    deathFrames = Phaser.Animations.generateFramesNames('death', 0, 5)
    // }
    // this.animations.add('death', deathFrames)
    // - can be used if some characters have different death animations

    this.animations.add('death', /* some default death frames */null, 8, false) // last argument is a toggle for looping the animation
    // assumes that death animation is same for all characters
    // generateFrameNames(spritesheetKey, startingFrame, lastFrame, suffix)
    const rates = {
      'idle': 2,
      'move': 16,
      'attack': 14
    }
    // defines frame rate of each animation type

    const animationPrefixes = ['idle', 'move', 'attack']
    const directions = ['up', 'down', 'left', 'right']

    for (const animationPrefix of animationPrefixes) {
      for (const direction of directions) {
        const animationType = `${animationPrefix}-${direction}`

        if (frames.hasOwnProperty(animationType)) {
          this.animations.add(animationType, frames[animationType], rates[animationPrefix], false)
          // do we auto attack targetted monsters/players?
        }
        // every character json or db information has a
      }
    }
  }

  displayHP() {

  }
}
<commit_msg>create basic prefab<commit_after>/* USE
- all characters should extend from entityPrefab constructor
- all characters will share qualities defined in entityPrefab
*/

/* todo
- define collision here?
*/
// todo: weapon prefab
// todo: health bar
// todo: activity feed
// todo: set death property on living entity
// todo; displayHP function that shows numeric value upon hp change, different color for heal and damage

export default class entityPrefab extends Phaser.Sprite {
  constructor(game, name, position, properties) {
    /* property considerations:
      sprite - player class, monster npc type, friendly npc type,
      group - necessary?,
    */

    /* frames considerations:
      at higher level class that extends from prefab should have a this.frames property
      which is an object that stores multiple key value pairs where the key is animation type and value represents the frames array
      frames object - {'animationTypeOne': [frames], 'animationTypeTwo': [frames]}
    */

    super(game, position.x, position.y, properties.spriteKey, properties.initialFrame)

    // this.gameState = game
    // may not need this
    this.name = name
    this.initialFrame = properties.initalFrame
    this.attackTarget = null

    if (properties.group) {
      this.gameState.groups[properties.group].children.push(this)
      // gameState has groups object that stores all group types
    }

    game.add.existing(this)
    // adds current prefab to the gameState

    game.physics.p2.enable(this)

    game.prefabs[name] = this
    // don't need this?
    // gameState has prefabs object that allows access to current prefab sprite?
  }

  // phaser quest approach
  setAnimationFrames() {
    // add animations for 'idle' move' 'death' 'attack' to the sprite object entity
    // if playable character, the animation should be set to weapon as well
    const frames = this.frames

    // let deathFrames
    // if (frames.hasOwnProperty('death')) {
    //   deathFrames = Phaser.Animations.generateFrameNames(`${this.name}-death`, frames[death][0], frames[death][1])
    // } else {
    //    deathFrames = Phaser.Animations.generateFramesNames('death', 0, 5)
    // }
    // this.animations.add('death', deathFrames)
    // - can be used if some characters have different death animations

    this.animations.add('death', /* some default death frames */null, 8, false) // last argument is a toggle for looping the animation
    // assumes that death animation is same for all characters
    // generateFrameNames(spritesheetKey, startingFrame, lastFrame, suffix)
    const rates = {
      'idle': 2,
      'move': 16,
      'attack': 14
    }
    // defines frame rate of each animation type

    const animationPrefixes = ['idle', 'move', 'attack']
    const directions = ['up', 'down', 'left', 'right']

    for (const animationPrefix of animationPrefixes) {
      for (const direction of directions) {
        const animationType = `${animationPrefix}-${direction}`

        if (frames.hasOwnProperty(animationType)) {
          this.animations.add(animationType, frames[animationType], rates[animationPrefix], false)
          // do we auto attack targetted monsters/players?
        }
        // every character json or db information has a
      }
    }
  }

  displayHP() {

  }
}
<|endoftext|>