<commit_before>// Functions for the mobile version
$(document).on('click', '#open_main_menu', openMobileMenu);

// Add swipe detection
$(document).on('ready', detectMobileScreen);

var screenWidth;
var menuOpen = false;

function detectMobileScreen() {
  screenWidth = $(window).outerWidth();
  if (screenWidth < 768) {
    if (!menuOpen) {
      $('.finger-detection-open-menu').on('swiperight', openMobileMenu);
    }
  }
}

function openMobileMenu () {
  if (menuOpen) {
    $('aside').css({'left': '-250px'});
    menuOpen = false;
  } else {
    $('aside').css({'left': '0px'});
    menuOpen = true;
    $('aside').on('swipeleft', openMobileMenu);
  }
}

var scrolled, mainSectionHeight, headerHeight, containerHeight;

// always initiate the scroll at the top
$(window).on('beforeunload', function() {
  $(window).scrollTop(0);
});

// get the height of the browser screen
$(window).on('resize', function() {
  headerHeight = $('header').outerHeight();
  mainSectionHeight = $('#opensuse-os').outerHeight() - headerHeight;
  //remove the height in the container of the main section 'home'
  $('#opensuse-os').css('height', '')
  containerHeight = $('#opensuse-os').outerHeight() + 30
})

$(window).bind('scroll',function(e){
  getScrolledData();
});

var $mainMenu;

$(function() {
  $mainMenu = $('#main-menu').html()
  $('aside').html($mainMenu)
  headerHeight = $('header').outerHeight();
  mainSectionHeight = $('#opensuse-os').outerHeight() - headerHeight;
})

var scrolledDown = false;

function getScrolledData() {
  scrolled = $(window).scrollTop();

  // Go to Top
  if ($(window).outerHeight()/2 < scrolled) {
    $(".go-to-top").fadeIn();
  }
  else {
    $(".go-to-top").fadeOut();
  }

  // detect if the user has scrolled more than the first section (height) to reduce the size of the menu
  if (scrolled > mainSectionHeight) {
    headerChanges()
    scrolledDown = true;
  }

  if (scrolledDown && scrolled < mainSectionHeight) {
    headerReset()
  }
}

function headerChanges() {
  $('header').css({
    background: moreInfoOpened ? '#6da741' : '#173f4f',
    top: '0px',
    height: '45px',
    padding: '8px',
    'z-index': '1000'
  })
  $('#opensuseLogo').css({
    height: '25px'
  })
  $('header ul li a').css({
    'font-size': '14px',
    'color': '#fff'
  })

}
function headerReset() {
  $('header').removeAttr('style')
  //but always keep the color applied from the scrolling
  $('header').css({
    background: moreInfoOpened ? '#6da741' : '#173f4f'
  })
  $('#opensuseLogo').removeAttr('style')
  $('header ul li a').removeAttr('style')
  $('header ul li a').css({
    'color': moreInfoOpened ? '#fff' : ''
  })
}

// init WOW.js
wow = new WOW(
  {
    offset: 30
  }
)
wow.init();

// init OWL slider

$(document).ready(function() {
  $("#owl-slide-news").owlCarousel({

  navigation : true,
  slideSpeed : 300,
  paginationSpeed : 400,
  singleItem : true,
  navigationText : ["",""]
  });
});

// tumbleweed opensuse more information

var moreInfoOpened = false;
var $osSelected, title, text, icon;

$(function() {
  $('#tumbleweed').on('click', function() {
    osMoreInformation($(this))
  })
  $('#openSUSE').on('click', function() {
    osMoreInformation($(this))
  })
})

function osMoreInformation(os) {

  moreInfoOpened = true
  //get the height of the main container
  containerHeight = $('#opensuse-os').outerHeight();

  //find the information of the selected distribution
  $osSelected = os
  osSelectedTitle = $osSelected.find("h1").html()
  osSelectedText = $osSelected.find(".hidden-content").html()
  osSelectedIcon = $osSelected.find(".distributions-icon").html()

  window.location.hash = osSelectedTitle;

  //dont let users click more than once
  $osSelected.addClass('not-clickable')

  // animation
  $('#opensuse-os .container-fluid').addClass('animated bounceOut')
  $('#opensuse-os').css({
    background: '#6da741'
  })
  $('header').css({
    background: moreInfoOpened ? '#6da741' : '#173f4f'
  })
  $('header ul li a').css({
    color: "#fff"
  })

  setTimeout(hideLandingPageInfo, 800)
  setTimeout(createMoreInformationArea, 1300)

  function hideLandingPageInfo () {
    $('#opensuse-os').css({
      height: containerHeight + 'px'
    })
    $('#opensuse-os .container-fluid').hide()
  }
  function createMoreInformationArea () {
    information = '
'
                  + '

'
                  + '
'
                  + osSelectedTitle
                  + '
'
                  + '
'
                  + osSelectedText
                  + '
'
                  + '
'
                  + '
'
                  + ''
                  + 'Back to main page'
                  + '
'
                  + '
'
    $('#opensuse-os').append(information)
    $('.os-icon').html(osSelectedIcon)

    $('.back-to-main-page').on('click', function() {
      history.pushState('', document.title, window.location.pathname);
      backToMainPageOs($osSelected)
    })

    $('#home, #opensuseLogo').on('click', function() {
      history.pushState('', document.title, window.location.pathname);
      scrolled = $(window).scrollTop();
      if (scrolled > mainSectionHeight) {
        setTimeout('backToMainPageOs($osSelected)', 900);

      } else
      {
        backToMainPageOs($osSelected)
      }
    })

  }
}

function backToMainPageOs (os) {
  moreInfoOpened = false;
  $('#more-information-os').addClass('animated bounceOut')
  $('header').removeAttr('style')
  $('header ul li a').removeAttr('style')
  $('#opensuse-os').removeAttr('style').css({
      height: containerHeight + 'px'
    })

  setTimeout(hideMoreInformation, 800)
  setTimeout(showMainInformation, 1300)

  function hideMoreInformation () {
    $('#more-information-os').hide()
    $('#more-information-os').remove()

  }

  function showMainInformation () {
    $('#opensuse-os .container-fluid').removeClass('animated bounceOut').show().addClass('animated bounceIn')
  }

  //make the area clickable again
  $osSelected = os
  $osSelected.removeClass('not-clickable')

}

//*****************init i18n

var lang = new Lang('en');
//languages setup - please list here all new language packs
window.lang.dynamic('ar', 'assets/js/langpack/ar.json');
window.lang.dynamic('ast', 'assets/js/langpack/ast.json');
window.lang.dynamic('ca', 'assets/js/langpack/ca.json');
window.lang.dynamic('cs', 'assets/js/langpack/cs.json');
window.lang.dynamic('da', 'assets/js/langpack/da.json');
window.lang.dynamic('de', 'assets/js/langpack/de.json');
window.lang.dynamic('el', 'assets/js/langpack/el.json');
window.lang.dynamic('es', 'assets/js/langpack/es.json');
window.lang.dynamic('fa', 'assets/js/langpack/fa.json');
window.lang.dynamic('fi', 'assets/js/langpack/fi.json');
window.lang.dynamic('fr', 'assets/js/langpack/fr.json');
window.lang.dynamic('gl', 'assets/js/langpack/gl.json');
window.lang.dynamic('hi', 'assets/js/langpack/hi.json');
window.lang.dynamic('hy', 'assets/js/langpack/hy.json');
window.lang.dynamic('id', 'assets/js/langpack/id.json');
window.lang.dynamic('it', 'assets/js/langpack/it.json');
window.lang.dynamic('ja', 'assets/js/langpack/ja.json');
window.lang.dynamic('kab', 'assets/js/langpack/kab.json');
window.lang.dynamic('ko', 'assets/js/langpack/ko.json');
window.lang.dynamic('lt', 'assets/js/langpack/lt.json');
window.lang.dynamic('nl', 'assets/js/langpack/nl.json');
window.lang.dynamic('nn', 'assets/js/langpack/nn.json');
window.lang.dynamic('pl', 'assets/js/langpack/pl.json');
window.lang.dynamic('pt_BR', 'assets/js/langpack/pt_BR.json');
window.lang.dynamic('ru', 'assets/js/langpack/ru.json');
window.lang.dynamic('sk', 'assets/js/langpack/sk.json');
window.lang.dynamic('sv', 'assets/js/langpack/sv.json');
window.lang.dynamic('uk', 'assets/js/langpack/uk.json');
window.lang.dynamic('zh_CN', 'assets/js/langpack/zh_CN.json');
window.lang.dynamic('zh_TW', 'assets/js/langpack/zh_TW.json');

//change language on click
$(document).on("click", ".change-language", function() {
  var languageSelected = $(this).data('language-value');
  var languageString = $(this).html();
  $('.dropup_language-menu').removeClass('open');
  $("body").fadeOut(300, function() {
    window.lang.change(languageSelected);
    $(".selected-language").html(languageString);
    $(this).fadeIn(300);
  });

  return false;
})

//check if there is a langCookie in the browser
$(document).on("ready", function(){

  var languageCode;
  var selectedLanguageName;

  if (cookieLanguage === undefined) {
    try {
      // try to use navigator.language
      languageCode = navigator.language.replace("-","_");
      window.lang.change(languageCode);
    }
    catch(err) {
      // navigator.language is not available
      if (navigator.language.length > 2) {
        try {
          // try with a more general string (for example, if navigator.language is "es-ES" then "es" is tried)
          languageCode = navigator.language.substring(0,2);
          window.lang.change(languageCode);
        }
        catch(err) {
          languageCode = "en";
        }
      }
      else {
        languageCode = "en";
      }
    }
  }
  else {
    languageCode = cookieLanguage;
  }

  selectedLanguageName = $(".languages").find("[data-language-value='" + languageCode + "']").html();
  $(".selected-language").html(selectedLanguageName);

});
//*****************

//init particles background
/* Disabled for excessive CPU consumption
$(document).ready(function() {
  var colorParticles = 'rgba(255,255,255,0.07)'
  $('#opensuse-os').particleground({
    dotColor: colorParticles,
    lineColor: colorParticles
  });
});
*/

//Contribution interpolation

$(document).ready(function () {

  contributionInterpolation()

});

var contributionInterpolation = function () {
  $(document).on("click", '.contribute-code', function () {
    bounceBall($(this), 3, 250);
  })
  $(document).on("click", '.contribute-hardware', function () {
    bounceBall($(this), 3, 250);
  })

  function bounceBall(element, times, speed) {

    //dont let the user click on the ball while the description is open
    element.addClass('not-clickable');

    //add the class Active to the element
    element.addClass('active');

    //take the initial position of the element
    var x = element.offset().left - $(window).scrollLeft();
    var y = $(window).outerHeight() - (element.offset().top - $(window).scrollTop()) - element.outerHeight();
    var elementWidth = element.outerWidth();

    //make the element a position absolute element of the body removing it first from the original container
    var parent = element.parent();
    element.detach();
    $('#contribute-details').prepend(element).css({display: 'block'});
    //element.

    element.css({
      position: 'absolute',
      left: x + 'px',
      bottom: y + 'px',
      width: elementWidth + 'px'
    })

    for(var i = 0; i < times; i++) {
      distance =  y / (i+2) ;

      element.animate({bottom: 0}, speed, 'easeInQuad')
        .animate({bottom: '+='+distance}, speed, 'easeOutQuad');
      if (i === 2) {
        element.animate({bottom: 0}, 400, 'easeInQuad', function() {
          openContributionDetails()
        });
      }
    }

    var openContributionDetails = function () {
      var $closeDetails = '<button type="button" class="close-details btn btn-default" data-dismiss="modal" aria-label="Close">×</button>'
      var $detailsContent = parent.find('.hidden-content').html();
      var $details = "
" + $detailsContent + "
"

      $("#contribute-details").css({background: 'rgba(109, 167, 65, 0.9)'})
        .append($details).append($closeDetails);

      //close the details
      $('.close-details').on("click", function() {
        //remove the Animated class first, to restart the effect in case the user
        //clicks more than once on the element
        parent.prepend(element).removeClass('animated fadeInUp');
        $('#contribute-details').fadeOut(function() {
          $(this).empty().removeAttr('style');
          element.removeAttr('style').removeClass('active');
          parent.prepend(element).addClass('animated fadeInUp');
          element.removeClass('not-clickable');
        })
      });

    }
  }

}

// Add "openSUSE Linux OS" to the document Title
$(document).on("ready", function() {
  $("title").prepend('openSUSE - Linux OS. ')
})

// check if SVG is supported by the user's browser
$(document).on("ready", function(){
  if (!Modernizr.svg) {
    //replace all the svg images for png
    $("img").each(function() {
      var currentValue = $(this).attr("src");
      var newValue = currentValue.replace(".svg", ".png");
      $(this).attr("src", newValue)
    });
    //add a class to the background of Contribute so the background is a .jpg
    $("#contribute-to-opensuse").addClass('no-svg')
  }
})

// Facebook token
window.fbAsyncInit = function() {
  FB.init({
    appId : '831347386978737',
    xfbml : true,
    version : 'v2.4'
  });
};

(function(d, s, id){
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {return;}
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

window.onkeyup = function(e) {
  var key = e.keyCode ? e.keyCode : e.which;

  if (key == 8 || key == 27) {
    history.pushState('', document.title, window.location.pathname);
    backToMainPageOs($osSelected);
  }
}

<commit_msg>update laguages in opensuse-theme.js<commit_after>// Functions for the mobile version
$(document).on('click', '#open_main_menu', openMobileMenu);

// Add swipe detection
$(document).on('ready', detectMobileScreen);

var screenWidth;
var menuOpen = false;

function detectMobileScreen() {
  screenWidth = $(window).outerWidth();
  if (screenWidth < 768) {
    if (!menuOpen) {
      $('.finger-detection-open-menu').on('swiperight', openMobileMenu);
    }
  }
}

function openMobileMenu () {
  if (menuOpen) {
    $('aside').css({'left': '-250px'});
    menuOpen = false;
  } else {
    $('aside').css({'left': '0px'});
    menuOpen = true;
    $('aside').on('swipeleft', openMobileMenu);
  }
}

var scrolled, mainSectionHeight, headerHeight, containerHeight;

// always initiate the scroll at the top
$(window).on('beforeunload', function() {
  $(window).scrollTop(0);
});

// get the height of the browser screen
$(window).on('resize', function() {
  headerHeight = $('header').outerHeight();
  mainSectionHeight = $('#opensuse-os').outerHeight() - headerHeight;
  //remove the height in the container of the main section 'home'
  $('#opensuse-os').css('height', '')
  containerHeight = $('#opensuse-os').outerHeight() + 30
})

$(window).bind('scroll',function(e){
  getScrolledData();
});

var $mainMenu;

$(function() {
  $mainMenu = $('#main-menu').html()
  $('aside').html($mainMenu)
  headerHeight = $('header').outerHeight();
  mainSectionHeight = $('#opensuse-os').outerHeight() - headerHeight;
})

var scrolledDown = false;

function getScrolledData() {
  scrolled = $(window).scrollTop();

  // Go to Top
  if ($(window).outerHeight()/2 < scrolled) {
    $(".go-to-top").fadeIn();
  }
  else {
    $(".go-to-top").fadeOut();
  }

  // detect if the user has scrolled more than the first section (height) to reduce the size of the menu
  if (scrolled > mainSectionHeight) {
    headerChanges()
    scrolledDown = true;
  }

  if (scrolledDown && scrolled < mainSectionHeight) {
    headerReset()
  }
}

function headerChanges() {
  $('header').css({
    background: moreInfoOpened ? '#6da741' : '#173f4f',
    top: '0px',
    height: '45px',
    padding: '8px',
    'z-index': '1000'
  })
  $('#opensuseLogo').css({
    height: '25px'
  })
  $('header ul li a').css({
    'font-size': '14px',
    'color': '#fff'
  })

}
function headerReset() {
  $('header').removeAttr('style')
  //but always keep the color applied from the scrolling
  $('header').css({
    background: moreInfoOpened ? '#6da741' : '#173f4f'
  })
  $('#opensuseLogo').removeAttr('style')
  $('header ul li a').removeAttr('style')
  $('header ul li a').css({
    'color': moreInfoOpened ? '#fff' : ''
  })
}

// init WOW.js
wow = new WOW(
  {
    offset: 30
  }
)
wow.init();

// init OWL slider

$(document).ready(function() {
  $("#owl-slide-news").owlCarousel({

  navigation : true,
  slideSpeed : 300,
  paginationSpeed : 400,
  singleItem : true,
  navigationText : ["",""]
  });
});

// tumbleweed opensuse more information

var moreInfoOpened = false;
var $osSelected, title, text, icon;

$(function() {
  $('#tumbleweed').on('click', function() {
    osMoreInformation($(this))
  })
  $('#openSUSE').on('click', function() {
    osMoreInformation($(this))
  })
})

function osMoreInformation(os) {

  moreInfoOpened = true
  //get the height of the main container
  containerHeight = $('#opensuse-os').outerHeight();

  //find the information of the selected distribution
  $osSelected = os
  osSelectedTitle = $osSelected.find("h1").html()
  osSelectedText = $osSelected.find(".hidden-content").html()
  osSelectedIcon = $osSelected.find(".distributions-icon").html()

  window.location.hash = osSelectedTitle;

  //dont let users click more than once
  $osSelected.addClass('not-clickable')

  // animation
  $('#opensuse-os .container-fluid').addClass('animated bounceOut')
  $('#opensuse-os').css({
    background: '#6da741'
  })
  $('header').css({
    background: moreInfoOpened ? '#6da741' : '#173f4f'
  })
  $('header ul li a').css({
    color: "#fff"
  })

  setTimeout(hideLandingPageInfo, 800)
  setTimeout(createMoreInformationArea, 1300)

  function hideLandingPageInfo () {
    $('#opensuse-os').css({
      height: containerHeight + 'px'
    })
    $('#opensuse-os .container-fluid').hide()
  }
  function createMoreInformationArea () {
    information = '
'
                  + '

'
                  + '
'
                  + osSelectedTitle
                  + '
'
                  + '
'
                  + osSelectedText
                  + '
'
                  + '
'
                  + '
'
                  + ''
                  + 'Back to main page'
                  + '
'
                  + '
'
    $('#opensuse-os').append(information)
    $('.os-icon').html(osSelectedIcon)

    $('.back-to-main-page').on('click', function() {
      history.pushState('', document.title, window.location.pathname);
      backToMainPageOs($osSelected)
    })

    $('#home, #opensuseLogo').on('click', function() {
      history.pushState('', document.title, window.location.pathname);
      scrolled = $(window).scrollTop();
      if (scrolled > mainSectionHeight) {
        setTimeout('backToMainPageOs($osSelected)', 900);

      } else
      {
        backToMainPageOs($osSelected)
      }
    })

  }
}

function backToMainPageOs (os) {
  moreInfoOpened = false;
  $('#more-information-os').addClass('animated bounceOut')
  $('header').removeAttr('style')
  $('header ul li a').removeAttr('style')
  $('#opensuse-os').removeAttr('style').css({
      height: containerHeight + 'px'
    })

  setTimeout(hideMoreInformation, 800)
  setTimeout(showMainInformation, 1300)

  function hideMoreInformation () {
    $('#more-information-os').hide()
    $('#more-information-os').remove()

  }

  function showMainInformation () {
    $('#opensuse-os .container-fluid').removeClass('animated bounceOut').show().addClass('animated bounceIn')
  }

  //make the area clickable again
  $osSelected = os
  $osSelected.removeClass('not-clickable')

}

//*****************init i18n

var lang = new Lang('en');
//languages setup - please list here all new language packs
window.lang.dynamic('ar', 'assets/js/langpack/ar.json');
window.lang.dynamic('ast', 'assets/js/langpack/ast.json');
window.lang.dynamic('ca', 'assets/js/langpack/ca.json');
window.lang.dynamic('cs', 'assets/js/langpack/cs.json');
window.lang.dynamic('da', 'assets/js/langpack/da.json');
window.lang.dynamic('de', 'assets/js/langpack/de.json');
window.lang.dynamic('el', 'assets/js/langpack/el.json');
window.lang.dynamic('et', 'assets/js/langpack/et.json');
window.lang.dynamic('es', 'assets/js/langpack/es.json');
window.lang.dynamic('fa', 'assets/js/langpack/fa.json');
window.lang.dynamic('fi', 'assets/js/langpack/fi.json');
window.lang.dynamic('fr', 'assets/js/langpack/fr.json');
window.lang.dynamic('gl', 'assets/js/langpack/gl.json');
window.lang.dynamic('hy', 'assets/js/langpack/hy.json');
window.lang.dynamic('id', 'assets/js/langpack/id.json');
window.lang.dynamic('it', 'assets/js/langpack/it.json');
window.lang.dynamic('ja', 'assets/js/langpack/ja.json');
window.lang.dynamic('lt', 'assets/js/langpack/lt.json');
window.lang.dynamic('nl', 'assets/js/langpack/nl.json');
window.lang.dynamic('nn', 'assets/js/langpack/nn.json');
window.lang.dynamic('pl', 'assets/js/langpack/pl.json');
window.lang.dynamic('pt_BR', 'assets/js/langpack/pt_BR.json');
window.lang.dynamic('ru', 'assets/js/langpack/ru.json');
window.lang.dynamic('sk', 'assets/js/langpack/sk.json');
window.lang.dynamic('sv', 'assets/js/langpack/sv.json');
window.lang.dynamic('uk', 'assets/js/langpack/uk.json');
window.lang.dynamic('zh_CN', 'assets/js/langpack/zh_CN.json');
window.lang.dynamic('zh_TW', 'assets/js/langpack/zh_TW.json');

//change language on click
$(document).on("click", ".change-language", function() {
  var languageSelected = $(this).data('language-value');
  var languageString = $(this).html();
  $('.dropup_language-menu').removeClass('open');
  $("body").fadeOut(300, function() {
    window.lang.change(languageSelected);
    $(".selected-language").html(languageString);
    $(this).fadeIn(300);
  });

  return false;
})

//check if there is a langCookie in the browser
$(document).on("ready", function(){

  var languageCode;
  var selectedLanguageName;

  if (cookieLanguage === undefined) {
    try {
      // try to use navigator.language
      languageCode = navigator.language.replace("-","_");
      window.lang.change(languageCode);
    }
    catch(err) {
      // navigator.language is not available
      if (navigator.language.length > 2) {
        try {
          // try with a more general string (for example, if navigator.language is "es-ES" then "es" is tried)
          languageCode = navigator.language.substring(0,2);
          window.lang.change(languageCode);
        }
        catch(err) {
          languageCode = "en";
        }
      }
      else {
        languageCode = "en";
      }
    }
  }
  else {
    languageCode = cookieLanguage;
  }

  selectedLanguageName = $(".languages").find("[data-language-value='" + languageCode + "']").html();
  $(".selected-language").html(selectedLanguageName);

});
//*****************

//init particles background
/* Disabled for excessive CPU consumption
$(document).ready(function() {
  var colorParticles = 'rgba(255,255,255,0.07)'
  $('#opensuse-os').particleground({
    dotColor: colorParticles,
    lineColor: colorParticles
  });
});
*/

//Contribution interpolation

$(document).ready(function () {

  contributionInterpolation()

});

var contributionInterpolation = function () {
  $(document).on("click", '.contribute-code', function () {
    bounceBall($(this), 3, 250);
  })
  $(document).on("click", '.contribute-hardware', function () {
    bounceBall($(this), 3, 250);
  })

  function bounceBall(element, times, speed) {

    //dont let the user click on the ball while the description is open
    element.addClass('not-clickable');

    //add the class Active to the element
    element.addClass('active');

    //take the initial position of the element
    var x = element.offset().left - $(window).scrollLeft();
    var y = $(window).outerHeight() - (element.offset().top - $(window).scrollTop()) - element.outerHeight();
    var elementWidth = element.outerWidth();

    //make the element a position absolute element of the body removing it first from the original container
    var parent = element.parent();
    element.detach();
    $('#contribute-details').prepend(element).css({display: 'block'});
    //element.

    element.css({
      position: 'absolute',
      left: x + 'px',
      bottom: y + 'px',
      width: elementWidth + 'px'
    })

    for(var i = 0; i < times; i++) {
      distance =  y / (i+2) ;

      element.animate({bottom: 0}, speed, 'easeInQuad')
        .animate({bottom: '+='+distance}, speed, 'easeOutQuad');
      if (i === 2) {
        element.animate({bottom: 0}, 400, 'easeInQuad', function() {
          openContributionDetails()
        });
      }
    }

    var openContributionDetails = function () {
      var $closeDetails = '<button type="button" class="close-details btn btn-default" data-dismiss="modal" aria-label="Close">×</button>'
      var $detailsContent = parent.find('.hidden-content').html();
      var $details = "
" + $detailsContent + "
"

      $("#contribute-details").css({background: 'rgba(109, 167, 65, 0.9)'})
        .append($details).append($closeDetails);

      //close the details
      $('.close-details').on("click", function() {
        //remove the Animated class first, to restart the effect in case the user
        //clicks more than once on the element
        parent.prepend(element).removeClass('animated fadeInUp');
        $('#contribute-details').fadeOut(function() {
          $(this).empty().removeAttr('style');
          element.removeAttr('style').removeClass('active');
          parent.prepend(element).addClass('animated fadeInUp');
          element.removeClass('not-clickable');
        })
      });

    }
  }

}

// Add "openSUSE Linux OS" to the document Title
$(document).on("ready", function() {
  $("title").prepend('openSUSE - Linux OS. ')
})

// check if SVG is supported by the user's browser
$(document).on("ready", function(){
  if (!Modernizr.svg) {
    //replace all the svg images for png
    $("img").each(function() {
      var currentValue = $(this).attr("src");
      var newValue = currentValue.replace(".svg", ".png");
      $(this).attr("src", newValue)
    });
    //add a class to the background of Contribute so the background is a .jpg
    $("#contribute-to-opensuse").addClass('no-svg')
  }
})

// Facebook token
window.fbAsyncInit = function() {
  FB.init({
    appId : '831347386978737',
    xfbml : true,
    version : 'v2.4'
  });
};

(function(d, s, id){
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) {return;}
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

window.onkeyup = function(e) {
  var key = e.keyCode ? e.keyCode : e.which;

  if (key == 8 || key == 27) {
    history.pushState('', document.title, window.location.pathname);
    backToMainPageOs($osSelected);
  }
}

<|endoftext|>


<commit_before>import React from 'react-native';
import relativeDate from '../utils/relative-date';
import Api from '../api';

let {
  View,
  Text,
  StyleSheet,
  Image,
  ListView
} = React;

var styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white'
  },
  detail: {
    flex: 1,
    alignItems: 'flex-start',
    flexDirection: 'row',
    padding: 10
  },
  textContainer: {
    flex: 1
  },
  cellImage: {
    height: 60,
    borderRadius: 30,
    marginRight: 10,
    width: 60
  },
  title: {
    flex: 1,
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 2
  },
  info: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between'
  },
  domain: {
    color: '#999999',
    fontSize: 12
  },
  time: {
    fontSize: 12,
    color: '#cccccc'
  }
});

class Topic extends React.Component {
  constructor(props) {
    super(props);

    let ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => {
        return r1 !== r2;
      }
    });

    this.state = {
      dataSource: ds.cloneWithRows([]),
      loading: true
    };

    Api.getComments(this.props.data.subreddit, this.props.data.id).then((result) => {
      this.setState({
        detail: result.detail,
        dataSource: this.state.dataSource.cloneWithRows(result.comments),
        loading: false
      });
    });
  }

  renderRow(item) {
    return (
      <View style={styles.row}>
        <View style={styles.textContainer}>
          <Text style={styles.domain}>
            {item.author}
          </Text>
          <Text style={styles.title}>
            {item.text}
          </Text>
        </View>
        <View style={styles.cellBorder} />
      </View>
    );
  }

  render() {
    if (this.state.loading) {
      return <Text>Loading</Text>;
    }

    let item = this.state.detail;
    let image = item.image ? (
      <Image
      source={ { uri: item.image } }
      style={styles.cellImage}
      />
    ) : null;
    return (
      <View style={styles.container}>
        <View style={styles.detail}>
          {image}
          <View style={styles.textContainer}>
            <Text style={styles.title}>
              {item.title}
            </Text>
            <View style={styles.info}>
              <Text style={styles.domain} numberOfLines={1}>
                {item.domain}
              </Text>
              <Text style={styles.time} numberOfLines={1}>
                {relativeDate(item.created)}
              </Text>
            </View>
          </View>
        </View>
        <ListView
          dataSource={this.state.dataSource}
          renderRow={this.renderRow.bind(this)}
        />
      </View>
    );
  }
}

module.exports = Topic;
<commit_msg>better comment rendering<commit_after>import React from 'react-native';
import relativeDate from '../utils/relative-date';
import Api from '../api';

let {
  View,
  Text,
  StyleSheet,
  Image,
  ListView,
  ScrollView
} = React;

var styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    flexDirection: 'column'
  },

  detail: {
    flex: 1,
    alignItems: 'center',
    backgroundColor: 'white',
    flexDirection: 'row',
    padding: 10
  },

  comments: {
    padding: 10
  },

  textContainer: {
    flex: 1
  },
  cellImage: {
    height: 60,
    borderRadius: 30,
    marginRight: 10,
    width: 60
  },
  title: {
    flex: 1,
    fontSize: 16,
    fontWeight: 'bold',
    marginBottom: 2
  },
  info: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-between'
  },
  domain: {
    color: '#999999',
    fontSize: 12
  },
  time: {
    fontSize: 12,
    color: '#cccccc'
  }
});

class Topic extends React.Component {
  constructor(props) {
    super(props);

    let ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => {
        return r1 !== r2;
      }
    });

    this.state = {
      dataSource: ds.cloneWithRows([]),
      loading: true
    };

    Api.getComments(this.props.data.subreddit, this.props.data.id).then((result) => {
      this.setState({
        detail: result.detail,
        dataSource: this.state.dataSource.cloneWithRows(result.comments),
        loading: false
      });
    });
  }

  renderComment(item) {
    return (
      <View style={styles.row}>
        <View style={styles.textContainer}>
          <Text style={styles.domain}>
            {item.author}
          </Text>
          <Text style={styles.title}>
            {item.text}
          </Text>
        </View>
        <View style={styles.cellBorder} />
      </View>
    );
  }

  render() {
    if (this.state.loading) {
      return <Text>Loading</Text>;
    }

    let item = this.state.detail;
    let image = item.image ? (
      <Image
      source={ { uri: item.image } }
      style={styles.cellImage}
      />
    ) : null;
    return (
      <View style={styles.container}>
        <ScrollView>
          <View>
            <View style={styles.detail}>
              {image}
              <View style={styles.textContainer}>
                <Text style={styles.title}>
                  {item.title}
                </Text>
                <View style={styles.info}>
                  <Text style={styles.domain} numberOfLines={1}>
                    {item.domain}
                  </Text>
                  <Text style={styles.time} numberOfLines={1}>
                    {relativeDate(item.created)}
                  </Text>
                </View>
              </View>
            </View>
          </View>
          <View style={styles.comments}>
            <ListView
              dataSource={this.state.dataSource}
              renderRow={this.renderComment.bind(this)}
            />
          </View>
        </ScrollView>
      </View>
    );
  }
}

module.exports = Topic;
<|endoftext|>


<commit_before>//Describe view.
define([
  'jquery',
  'underscore',
  'backbone',
  'text!/templates/equations/equation.html',
  'js/models/feedback.js',
  'js/models/equation.js',
  'js/views/components.js',
  'js/collections/components.js'
], function($, _, Backbone, equationTemplate, Feedback, Equation, ComponentsView, ComponentsCollection) {
  var EquationView = Backbone.View.extend({

    events: {
      "submit .commentsForm": "submitComments",
      "click #updateEquation": "updateEquation"
    },

    //div.
    tagName:  "div",

    // Render the equation.
    render: function() {
      var compiledTemplate = _.template(equationTemplate)({equation: this.model});
      this.$el.html(compiledTemplate);
      var componentsView = new ComponentsView();
      componentsView.$el = this.$('#components');
      componentsView.collection = this.model.get("components");
      componentsView.render();
      componentsView.delegateEvents();
      return this;
    },

    submitComments: function(e) {
      var feedbackView = this;
      e.preventDefault();
      var feedback = new Feedback();

      var url = "/feedback?" + feedbackView.$('.commentsForm').serialize();
      $.ajax({
        type: "POST",
        url: url,
        dataType: 'json'
      }).done(function(data) {
        $("#commentsMessaging").html("Thank you for your feedback!");
        setTimeout(function() {
          $("#commentsMessaging").attr('tabindex', '-1').focus();
        }, 500);
      });
    },

    updateEquation: function(e) {
      e.preventDefault();
      var equationView = this;
      equationView.model.save({math: equationView.$("#equationMath").val()}, {
        success: function(model, response, options) {
          var updatedEquation = new Equation(response);
          var componentsView = new ComponentsView();
          componentsView.collection = new ComponentsCollection(updatedEquation.get("components"));
          equationView.$("#components").html(componentsView.render().el);
          setTimeout(function() {
            equationView.$("h2:first").attr('tabindex', '-1').focus();
          }, 500);
        },
        error: function(model, response, options) {
          equationView.$(".errorMessage").text("There was an error converting your math: " + response);
          setTimeout(function() {
            equationView.$(".errorMessage").attr('tabindex', '-1').focus();
          }, 500);
        }
      });
    }

  });
  return EquationView;
});
<commit_msg>MMLC-177 fix display of components after update<commit_after>//Describe view.
define([
  'jquery',
  'underscore',
  'backbone',
  'text!/templates/equations/equation.html',
  'js/models/feedback.js',
  'js/models/equation.js',
  'js/views/components.js',
  'js/collections/components.js'
], function($, _, Backbone, equationTemplate, Feedback, Equation, ComponentsView, ComponentsCollection) {
  var EquationView = Backbone.View.extend({

    events: {
      "submit .commentsForm": "submitComments",
      "click #updateEquation": "updateEquation"
    },

    //div.
    tagName:  "div",

    // Render the equation.
    render: function() {
      var compiledTemplate = _.template(equationTemplate)({equation: this.model});
      this.$el.html(compiledTemplate);
      var componentsView = new ComponentsView();
      componentsView.$el = this.$('#components');
      componentsView.collection = this.model.get("components");
      componentsView.render();
      componentsView.delegateEvents();
      return this;
    },

    submitComments: function(e) {
      var feedbackView = this;
      e.preventDefault();
      var feedback = new Feedback();

      var url = "/feedback?" + feedbackView.$('.commentsForm').serialize();
      $.ajax({
        type: "POST",
        url: url,
        dataType: 'json'
      }).done(function(data) {
        $("#commentsMessaging").html("Thank you for your feedback!");
        setTimeout(function() {
          $("#commentsMessaging").attr('tabindex', '-1').focus();
        }, 500);
      });
    },

    updateEquation: function(e) {
      e.preventDefault();
      var equationView = this;
      equationView.model.save({math: equationView.$("#equationMath").val()}, {
        success: function(model, response, options) {
          var updatedEquation = new Equation(response);
          var componentsView = new ComponentsView();
          componentsView.collection = updatedEquation.get("components");
          equationView.$("#components").html(componentsView.render().el);
          setTimeout(function() {
            equationView.$("h2:first").attr('tabindex', '-1').focus();
          }, 500);
        },
        error: function(model, response, options) {
          equationView.$(".errorMessage").text("There was an error converting your math: " + response);
          setTimeout(function() {
            equationView.$(".errorMessage").attr('tabindex', '-1').focus();
          }, 500);
        }
      });
    }

  });
  return EquationView;
});
<|endoftext|>


<commit_before>import React from 'react';
import check from 'check-types';
import classNames from 'classnames';
import { default as omit } from 'lodash.omit';

/**
 * Badge color enumerable.
 *
 * @type {Object}
 */
export const BadgeColors = {
  PRIMARY: 'primary',
  SECONDARY: 'secondary',
  SUCCESS: 'success',
  WARNING: 'warning',
  ALERT: 'alert'
};

/**
 * Badge component.
 * http://foundation.zurb.com/sites/docs/badge.html
 *
 * @param {Object} props
 * @returns {XML}
 */
export const Badge = props => {
  check.assert.maybe.string(props.color, 'Badge.props.color must be a string.');

  const className = classNames(
    props.className || 'badge',
    props.color
  );

  const omitProps = ['color'];

  return (
    <span {...omit(props, omitProps)} className={className}/>
  );
};

export default Badge;
<commit_msg>Fix badge component colors<commit_after>import React from 'react';
import check from 'check-types';
import classNames from 'classnames';
import { default as omit } from 'lodash.omit';

/**
 * Badge color enumerable.
 *
 * @type {Object}
 */
export const BadgeColors = {
  INFO: 'info',
  SECONDARY: 'secondary',
  SUCCESS: 'success',
  WARNING: 'warning',
  ALERT: 'alert'
};

/**
 * Badge component.
 * http://foundation.zurb.com/sites/docs/badge.html
 *
 * @param {Object} props
 * @returns {XML}
 */
export const Badge = props => {
  check.assert.maybe.string(props.color, 'Badge.props.color must be a string.');

  const className = classNames(
    props.className || 'badge',
    props.color
  );

  const omitProps = ['color'];

  return (
    <span {...omit(props, omitProps)} className={className}/>
  );
};

export default Badge;
<|endoftext|>


<commit_before>import _ from 'lodash';

import React from 'react';
import { Router, Route, Link } from 'react-router';
import Griddle from 'griddle-react';
import Loader from 'react-loader';
import { octokat, octokatHelper } from '../factory';
import * as helper from '../helper';
import Auth from '../auth';
import { dispatcher } from '../dispatcher';

import {
  Alert,
  Button,
  CollapsibleNav,
  Input,
  MenuItem,
  Modal,
  Nav,
  Navbar,
  NavBrand,
  NavDropdown,
  NavItem
} from 'react-bootstrap';

class AppRoute extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      error: null,
      user: null,
      authed: false,
      githubAccessToken: null,
      rateLimit: {},
      reset: new Date(),
      repos: [
        'oauth-io/oauth-js',
        'isaacs/github'
      ],
      showingAuthModal: false
    };

    dispatcher.register(payload => {
      if(payload.actionType === dispatcher.actionTypes.ERROR) {
        var error = payload.data;
        this.setState({error});
      }
    });
  }

  componentDidMount() {
    this.checkAuth();

    var checkRateLimit = () => {
      if (!octokat()) {
        setTimeout(checkRateLimit, 2000);
        return;
      }
      octokat().rateLimit.fetch().then(
        (data) => {
          var rateLimit = data.resources.core;
          var reset = data.resources.core.reset;
          var date = new Date(reset*1000);
          var state = {rateLimit, reset: date};
          this.setState(state);
          setTimeout(checkRateLimit, 2000);
        },
        () => {
          console.error(arguments);
        }
      );
    };
    checkRateLimit();
  }

  onClickSignIn() {
    this.showAuthModal();
  }

  onClickAuth() {
    this.showAuthModal();
  }

  showAuthModal() {
    this.setState({showingAuthModal: true});
  }

  signIn() {
    Auth.signIn().then(this.onSignedIn.bind(this));
  }

  onClickSignOut() {
    console.log('onClickSignOut');
    Auth.signOut().
      then(d => {
        this.setState({authed: false, user: null})
      });
  }

  checkAuth(options) {
    Auth.check(options).
      then(d => {
        console.log('authed', d);
        this.setState({githubAccessToken: d.githubAccessToken})
        this.onSignedIn();
      });
  }

  onSignedIn() {
    this.setState({authed: true});

    octokat().user.fetch().then(user => {
      console.log(user);
      this.setState({user});
    });
  }

  signInFromAlert() {
    this.dismissAlert();
    this.signIn();
  }

  dismissAlert() {
    this.setState({error: null});
  }

  closeAuthModal() {
    this.setState({showingAuthModal: false});
  }

  onChangeGitHubAccessToken(e) {
    var githubAccessToken = e.target.value;
    this.setState({githubAccessToken});
    Auth.setToken(githubAccessToken).
      then(d => {
        this.onSignedIn();
      });
  }

  render() {
    var children = this.props.children;

    if (! children) {
      children = (

          {this.state.repos.map(r => {
            return (

                <Link to={'/' + r}>{r}</Link>

            );
          })}

      );
    }

    var errorCmp;
    var error = this.state.error;
    if (this.state.error) {
      var message = error.message || error;
      errorCmp =
        <Alert bsStyle="danger" onDismiss={this.dismissAlert.bind(this)}>

Oh snap! You got an error!

{message}

            <Button onClick={this.onClickSignIn.bind(this)} bsStyle="success">Sign In</Button>
             or
            <Button onClick={this.dismissAlert.bind(this)}>Hide Alert</Button>

        </Alert>;
    }

    var authModalSignInCmp;
    if (! this.state.user) {
      authModalSignInCmp = (
        <Button
          bsStyle="success"
          onClick={this.signIn.bind(this)}
        >
          Sign In to GitHub via OAuth.io
        </Button>
      );
    }
    else {
      authModalSignInCmp = (

              @{this.state.user.login}

            <Button
              bsStyle="success"
              onClick={this.onClickSignOut.bind(this)}
            >
               Sign Out
            </Button>

      );
    }

    var authBarCmp;
    if (! this.state.user) {
      /*
       * https://github.com/react-bootstrap/react-bootstrap/issues/1404
       */
      authBarCmp = (
        <button type="button"
          className="btn btn-success navbar-btn navbar-right"
          onClick={this.onClickSignIn.bind(this)}
        >
          Sign In
        </button>
      );
    }
    else {
      var avatar = (

      );
      authBarCmp = (

          <NavDropdown eventKey={2}
            title={avatar}
            id="ghir-navbar-user-dropdown"
          >
            <MenuItem eventKey={5}
              onSelect={this.onClickAuth.bind(this)}
            >
               Authentication
            </MenuItem>
            <MenuItem eventKey={5}
              onSelect={this.onClickSignOut.bind(this)}
            >
               Sign Out
            </MenuItem>
          </NavDropdown>

      );
    }

    return (

        <Navbar toggleNavKey={0}>
          <NavBrand>
            <Link to="/">GitHub Issue Rank</Link>
          </NavBrand>
          <CollapsibleNav eventKey={0}>

              <NavDropdown eventKey={3}
                title={}
                id="ghir-navbar-more-dropdown"
              >
                <MenuItem eventKey={1}>
                   Settings
                </MenuItem>
                <MenuItem divider />
                <MenuItem eventKey={4}
                  href="https://github.com/AndersDJohnson/github-issue-rank"
                  target="_blank"
                >
                   Source Code
                </MenuItem>
              </NavDropdown>

            {authBarCmp}

          </CollapsibleNav>
        </Navbar>

        <Modal show={this.state.showingAuthModal} onHide={this.closeAuthModal.bind(this)}>
          <Modal.Header closeButton>
            <Modal.Title>Authentication</Modal.Title>
          </Modal.Header>
          <Modal.Body>

            {authModalSignInCmp}

Or provide an access token:

            <Input
              type="text"
              value={this.state.githubAccessToken}
              onChange={this.onChangeGitHubAccessToken.bind(this)}
            />

          </Modal.Body>
          <Modal.Footer>
            <Button
              onClick={this.closeAuthModal.bind(this)}
            >
              Close
            </Button>
          </Modal.Footer>
        </Modal>

        {errorCmp}

          <progress id="gh-api-limit"
            title="API Limit"
            value={this.state.rateLimit.remaining}
            max={this.state.rateLimit.limit} />

            API Limit {this.state.rateLimit.remaining} / {this.state.rateLimit.limit}
             (resets {this.state.reset.toString()})

        {children}

    )
  }
};

class NoRoute extends React.Component {
  componentDidMount() {
    console.log(this.props.params);
  }

  render() {
    return (

404

    )
  }
};

class LinkComponent extends React.Component {
  render() {
    var data = this.data();
    var {owner, repo, number} = this.props.rowData;
    var href = '/' + owner + '/' + repo + '/' + number;
    return <Link to={href} target="_blank">{data}</Link>;
  }
  data() {
    return this.props.data;
  }
};

class IssueNumberComponent extends LinkComponent {
  data() {
    var data = this.props.data;
    return data ? '#' + data : '';
  }
};

class RepoRoute extends React.Component {
  constructor(props) {
    super(props);

    var columnMetadata = [
      {
        columnName: 'number',
        displayName: '#',
        customComponent: IssueNumberComponent,
        cssClassName: 'griddle-column-number'
      },
      {
        columnName: 'title',
        displayName: 'Title',
        customComponent: LinkComponent,
        cssClassName: 'griddle-column-title'
      },
      {
        columnName: 'voteCount',
        displayName: '# Votes',
        customComponent: LinkComponent,
        cssClassName: 'griddle-column-voteCount'
      },
      {
        columnName: 'owner',
        visible: false
      },
      {
        columnName: 'repo',
        visible: false
      },
      {
        columnName: 'htmlUrl',
        visible: false
      }
    ];

    columnMetadata = _.each(columnMetadata, (md, i) => { md.order = i; })

    var columns =_.chain(columnMetadata)
      .sortBy('order')
      .filter((md) => {
        return md.visible == null ? true : false;
      })
      .pluck('columnName')
      .value();

    this.state = {
      owner: null,
      repo: null,
      rows: [],
      loaded: false,
      anyLoaded: false,
      columnMetadata,
      columns,
      progress: {
        value:0,
        max: 0
      }
    };
  }

  componentDidUpdate() {
    this.unmounting = false;
    this.showRepo();
  }

  componentDidMount() {
    this.unmounting = false;
    this.showRepo();
  }

  componentWillUnmount () {
    // allows us to ignore an inflight request in scenario 4
    this.unmounting = true;
    this.owner = null;
    this.repo = null;
  }

  sameState(owner, repo) {
    return (! this.unmounting) && (owner && (owner === this.state.owner)) && (repo && (repo === this.state.repo));
  }

  showRepo() {
    var {owner, repo} = this.props.params;

    if (this.sameState(owner, repo)) return;

    this.setState({
      loaded: false,
      owner: owner,
      repo: repo,
      rows: []
    });

    Auth.wait().then(() => {
      helper.showRepo(owner, repo,
        (err, rows, cancel, progress) => {
          if (err) {
            return dispatcher.error(err);
          }
          if ( ! this.sameState(owner, repo)) return cancel();
          this.showRows(err, rows);
          this.setState({
            anyLoaded: true,
            progress
          });
        },
        (err, rows, cancel, progress) => {
          // console.log('progress', progress);
          if (err) {
            this.setState({loaded: true, anyLoaded: true})
            return dispatcher.error(err);
          }
          if ( ! this.sameState(owner, repo)) return cancel();
          this.showRows(err, rows);
          this.setState({
            loaded: true,
            progress
          });
        }
      );
    });

  }

  showRows(err, rows) {
    if (! this.unmounting) {
      this.setState({
        rows
      });
    }
  }

  render() {
    var {owner, repo} = this.props.params;

    return (

          <Link to={'/' + owner + '/' + repo}>
            {owner}/{repo}
          </Link>

        <progress
          value={this.state.progress.value}
          max={this.state.progress.max}
        ></progress>

        <Loader loaded={this.state.loaded}></Loader>

        <Loader loaded={this.state.anyLoaded}>

# issues: {this.state.rows.length}

          <Griddle
            results={this.state.rows}
            columnMetadata={this.state.columnMetadata}
            columns={this.state.columns}
            resultsPerPage={10}
            showSettings={true}
            showFilter={true}
          />
        </Loader>

    )
  }
};

class IssueRoute extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      owner: null,
      repo: null,
      number: null,
      issue: {},
      comments: [],
      commentsWithVotes: [],
      loaded: false
    };
  }

  componentDidMount() {
    this.unmounting = false;
    this.showComments();
  }

  showComments() {
    var {owner, repo, number} = this.props.params;

    octokat()
      .repos(owner, repo)
      .issues(number)
      .fetch()
      .then(issue => {
        // console.log('issue', issue);
        this.setState({issue});
      }, (err) => {
        if (err) throw err;
      });

    octokatHelper().getComments(
      owner, repo, number,
      (err, comments, cancel) => {
        if (err) {
          return dispatcher.error(err);
        }

        // console.log('each', err, comments, cancel);
        comments = helper.mapCommentsHaveVotes(comments);
        this.setState({comments});
        var commentsWithVotes = comments.filter(c => {
          return c.hasVote;
        });
        this.setState({commentsWithVotes});
      },
      (err, comments) => {
        if (err) {
          return dispatcher.error(err);
        }
        // console.log('done', comments);
      }
    );
  }

  render() {
    var {owner, repo, number} = this.props.params;
    return (

          <Link to={'/' + owner + '/' + repo}>
            {owner}/{repo}
          </Link>

          <Link to={'/' + owner + '/' + repo + '/' + number}>
            #{number}
          </Link>

          {this.state.issue.title}

          {this.state.commentsWithVotes.map(c => {
            return (

            );
          })}

    );
  }
};

export class RouterComponent extends React.Component {
  render() {
    return (
      <Router>
        <Route path="/" component={AppRoute}>
          <Route path=":owner/:repo" component={RepoRoute}/>
          <Route path=":owner/:repo/:number" component={IssueRoute}/>
          <Route path="*" component={NoRoute}/>
        </Route>
      </Router>
    );
  }
};
<commit_msg>Await before comments on issue route.<commit_after>import _ from 'lodash';

import React from 'react';
import { Router, Route, Link } from 'react-router';
import Griddle from 'griddle-react';
import Loader from 'react-loader';
import { octokat, octokatHelper } from '../factory';
import * as helper from '../helper';
import Auth from '../auth';
import { dispatcher } from '../dispatcher';

import {
  Alert,
  Button,
  CollapsibleNav,
  Input,
  MenuItem,
  Modal,
  Nav,
  Navbar,
  NavBrand,
  NavDropdown,
  NavItem
} from 'react-bootstrap';

class AppRoute extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      error: null,
      user: null,
      authed: false,
      githubAccessToken: null,
      rateLimit: {},
      reset: new Date(),
      repos: [
        'oauth-io/oauth-js',
        'isaacs/github'
      ],
      showingAuthModal: false
    };

    dispatcher.register(payload => {
      if(payload.actionType === dispatcher.actionTypes.ERROR) {
        var error = payload.data;
        this.setState({error});
      }
    });
  }

  componentDidMount() {
    this.checkAuth();

    var checkRateLimit = () => {
      if (!octokat()) {
        setTimeout(checkRateLimit, 2000);
        return;
      }
      octokat().rateLimit.fetch().then(
        (data) => {
          var rateLimit = data.resources.core;
          var reset = data.resources.core.reset;
          var date = new Date(reset*1000);
          var state = {rateLimit, reset: date};
          this.setState(state);
          setTimeout(checkRateLimit, 2000);
        },
        () => {
          console.error(arguments);
        }
      );
    };
    checkRateLimit();
  }

  onClickSignIn() {
    this.showAuthModal();
  }

  onClickAuth() {
    this.showAuthModal();
  }

  showAuthModal() {
    this.setState({showingAuthModal: true});
  }

  signIn() {
    Auth.signIn().then(this.onSignedIn.bind(this));
  }

  onClickSignOut() {
    console.log('onClickSignOut');
    Auth.signOut().
      then(d => {
        this.setState({authed: false, user: null})
      });
  }

  checkAuth(options) {
    Auth.check(options).
      then(d => {
        console.log('authed', d);
        this.setState({githubAccessToken: d.githubAccessToken})
        this.onSignedIn();
      });
  }

  onSignedIn() {
    this.setState({authed: true});

    octokat().user.fetch().then(user => {
      console.log(user);
      this.setState({user});
    });
  }

  signInFromAlert() {
    this.dismissAlert();
    this.signIn();
  }

  dismissAlert() {
    this.setState({error: null});
  }

  closeAuthModal() {
    this.setState({showingAuthModal: false});
  }

  onChangeGitHubAccessToken(e) {
    var githubAccessToken = e.target.value;
    this.setState({githubAccessToken});
    Auth.setToken(githubAccessToken).
      then(d => {
        this.onSignedIn();
      });
  }

  render() {
    var children = this.props.children;

    if (! children) {
      children = (

          {this.state.repos.map(r => {
            return (

                <Link to={'/' + r}>{r}</Link>

            );
          })}

      );
    }

    var errorCmp;
    var error = this.state.error;
    if (this.state.error) {
      var message = error.message || error;
      errorCmp =
        <Alert bsStyle="danger" onDismiss={this.dismissAlert.bind(this)}>

Oh snap! You got an error!

{message}

            <Button onClick={this.onClickSignIn.bind(this)} bsStyle="success">Sign In</Button>
             or
            <Button onClick={this.dismissAlert.bind(this)}>Hide Alert</Button>

        </Alert>;
    }

    var authModalSignInCmp;
    if (! this.state.user) {
      authModalSignInCmp = (
        <Button
          bsStyle="success"
          onClick={this.signIn.bind(this)}
        >
          Sign In to GitHub via OAuth.io
        </Button>
      );
    }
    else {
      authModalSignInCmp = (

              @{this.state.user.login}

            <Button
              bsStyle="success"
              onClick={this.onClickSignOut.bind(this)}
            >
               Sign Out
            </Button>

      );
    }

    var authBarCmp;
    if (! this.state.user) {
      /*
       * https://github.com/react-bootstrap/react-bootstrap/issues/1404
       */
      authBarCmp = (
        <button type="button"
          className="btn btn-success navbar-btn navbar-right"
          onClick={this.onClickSignIn.bind(this)}
        >
          Sign In
        </button>
      );
    }
    else {
      var avatar = (

      );
      authBarCmp = (

          <NavDropdown eventKey={2}
            title={avatar}
            id="ghir-navbar-user-dropdown"
          >
            <MenuItem eventKey={5}
              onSelect={this.onClickAuth.bind(this)}
            >
               Authentication
            </MenuItem>
            <MenuItem eventKey={5}
              onSelect={this.onClickSignOut.bind(this)}
            >
               Sign Out
            </MenuItem>
          </NavDropdown>

      );
    }

    return (

        <Navbar toggleNavKey={0}>
          <NavBrand>
            <Link to="/">GitHub Issue Rank</Link>
          </NavBrand>
          <CollapsibleNav eventKey={0}>

              <NavDropdown eventKey={3}
                title={}
                id="ghir-navbar-more-dropdown"
              >
                <MenuItem eventKey={1}>
                   Settings
                </MenuItem>
                <MenuItem divider />
                <MenuItem eventKey={4}
                  href="https://github.com/AndersDJohnson/github-issue-rank"
                  target="_blank"
                >
                   Source Code
                </MenuItem>
              </NavDropdown>

            {authBarCmp}

          </CollapsibleNav>
        </Navbar>

        <Modal show={this.state.showingAuthModal} onHide={this.closeAuthModal.bind(this)}>
          <Modal.Header closeButton>
            <Modal.Title>Authentication</Modal.Title>
          </Modal.Header>
          <Modal.Body>

            {authModalSignInCmp}

Or provide an access token:

            <Input
              type="text"
              value={this.state.githubAccessToken}
              onChange={this.onChangeGitHubAccessToken.bind(this)}
            />

          </Modal.Body>
          <Modal.Footer>
            <Button
              onClick={this.closeAuthModal.bind(this)}
            >
              Close
            </Button>
          </Modal.Footer>
        </Modal>

        {errorCmp}

          <progress id="gh-api-limit"
            title="API Limit"
            value={this.state.rateLimit.remaining}
            max={this.state.rateLimit.limit} />

            API Limit {this.state.rateLimit.remaining} / {this.state.rateLimit.limit}
             (resets {this.state.reset.toString()})

        {children}

    )
  }
};

class NoRoute extends React.Component {
  componentDidMount() {
    console.log(this.props.params);
  }

  render() {
    return (

404

    )
  }
};

class LinkComponent extends React.Component {
  render() {
    var data = this.data();
    var {owner, repo, number} = this.props.rowData;
    var href = '/' + owner + '/' + repo + '/' + number;
    return <Link to={href} target="_blank">{data}</Link>;
  }
  data() {
    return this.props.data;
  }
};

class IssueNumberComponent extends LinkComponent {
  data() {
    var data = this.props.data;
    return data ? '#' + data : '';
  }
};

class RepoRoute extends React.Component {
  constructor(props) {
    super(props);

    var columnMetadata = [
      {
        columnName: 'number',
        displayName: '#',
        customComponent: IssueNumberComponent,
        cssClassName: 'griddle-column-number'
      },
      {
        columnName: 'title',
        displayName: 'Title',
        customComponent: LinkComponent,
        cssClassName: 'griddle-column-title'
      },
      {
        columnName: 'voteCount',
        displayName: '# Votes',
        customComponent: LinkComponent,
        cssClassName: 'griddle-column-voteCount'
      },
      {
        columnName: 'owner',
        visible: false
      },
      {
        columnName: 'repo',
        visible: false
      },
      {
        columnName: 'htmlUrl',
        visible: false
      }
    ];

    columnMetadata = _.each(columnMetadata, (md, i) => { md.order = i; })

    var columns =_.chain(columnMetadata)
      .sortBy('order')
      .filter((md) => {
        return md.visible == null ? true : false;
      })
      .pluck('columnName')
      .value();

    this.state = {
      owner: null,
      repo: null,
      rows: [],
      loaded: false,
      anyLoaded: false,
      columnMetadata,
      columns,
      progress: {
        value:0,
        max: 0
      }
    };
  }

  componentDidUpdate() {
    this.unmounting = false;
    this.showRepo();
  }

  componentDidMount() {
    this.unmounting = false;
    this.showRepo();
  }

  componentWillUnmount () {
    // allows us to ignore an inflight request in scenario 4
    this.unmounting = true;
    this.owner = null;
    this.repo = null;
  }

  sameState(owner, repo) {
    return (! this.unmounting) && (owner && (owner === this.state.owner)) && (repo && (repo === this.state.repo));
  }

  showRepo() {
    var {owner, repo} = this.props.params;

    if (this.sameState(owner, repo)) return;

    this.setState({
      loaded: false,
      owner: owner,
      repo: repo,
      rows: []
    });

    Auth.wait().then(() => {
      helper.showRepo(owner, repo,
        (err, rows, cancel, progress) => {
          if (err) {
            return dispatcher.error(err);
          }
          if ( ! this.sameState(owner, repo)) return cancel();
          this.showRows(err, rows);
          this.setState({
            anyLoaded: true,
            progress
          });
        },
        (err, rows, cancel, progress) => {
          // console.log('progress', progress);
          if (err) {
            this.setState({loaded: true, anyLoaded: true})
            return dispatcher.error(err);
          }
          if ( ! this.sameState(owner, repo)) return cancel();
          this.showRows(err, rows);
          this.setState({
            loaded: true,
            progress
          });
        }
      );
    });

  }

  showRows(err, rows) {
    if (! this.unmounting) {
      this.setState({
        rows
      });
    }
  }

  render() {
    var {owner, repo} = this.props.params;

    return (

          <Link to={'/' + owner + '/' + repo}>
            {owner}/{repo}
          </Link>

        <progress
          value={this.state.progress.value}
          max={this.state.progress.max}
        ></progress>

        <Loader loaded={this.state.loaded}></Loader>

        <Loader loaded={this.state.anyLoaded}>

# issues: {this.state.rows.length}

          <Griddle
            results={this.state.rows}
            columnMetadata={this.state.columnMetadata}
            columns={this.state.columns}
            resultsPerPage={10}
            showSettings={true}
            showFilter={true}
          />
        </Loader>

    )
  }
};

class IssueRoute extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      owner: null,
      repo: null,
      number: null,
      issue: {},
      comments: [],
      commentsWithVotes: [],
      loaded: false
    };
  }

  componentDidMount() {
    this.unmounting = false;
    this.showComments();
  }

  showComments() {
    var {owner, repo, number} = this.props.params;

    Auth.wait().then(() => {
      octokat()
        .repos(owner, repo)
        .issues(number)
        .fetch()
        .then(issue => {
          // console.log('issue', issue);
          this.setState({issue});
        }, (err) => {
          if (err) throw err;
        });

      octokatHelper().getComments(
        owner, repo, number,
        (err, comments, cancel) => {
          if (err) {
            return dispatcher.error(err);
          }

          // console.log('each', err, comments, cancel);
          comments = helper.mapCommentsHaveVotes(comments);
          this.setState({comments});
          var commentsWithVotes = comments.filter(c => {
            return c.hasVote;
          });
          this.setState({commentsWithVotes});
        },
        (err, comments) => {
          if (err) {
            return dispatcher.error(err);
          }
          // console.log('done', comments);
        }
      );
    });
  }

  render() {
    var {owner, repo, number} = this.props.params;
    return (

          <Link to={'/' + owner + '/' + repo}>
            {owner}/{repo}
          </Link>

          <Link to={'/' + owner + '/' + repo + '/' + number}>
            #{number}
          </Link>

          {this.state.issue.title}

          {this.state.commentsWithVotes.map(c => {
            return (

            );
          })}

    );
  }
};

export class RouterComponent extends React.Component {
  render() {
    return (
      <Router>
        <Route path="/" component={AppRoute}>
          <Route path=":owner/:repo" component={RepoRoute}/>
          <Route path=":owner/:repo/:number" component={IssueRoute}/>
          <Route path="*" component={NoRoute}/>
        </Route>
      </Router>
    );
  }
};
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { Route, BrowserRouter, Redirect, Switch } from 'react-router-dom'
import Login from './Login'
import Register from './Register'
import Home from './Home'
import Main from './protected/Main'
import Create from './protected/Create'
import Join from './protected/Join'
import { firebaseAuth } from '../config/constants'
import Navbar from './Navbar'

function PrivateRoute({
  component: Component,
  authed,
  ...rest
}) {
  return (
    <Route
      {...rest}
      render={(props) => authed === true
        ? <Component {...props} />
        : <Redirect
          to={{
            pathname: '/login',
            state: {
              from: props.location
            }
          }} />} />
  )
}

function PublicRoute({
  component: Component,
  authed,
  ...rest
}) {
  return (
    <Route
      {...rest}
      render={(props) => authed === false
        ? <Component {...props} />
        : <Redirect to='/main' />} />
  )
}

export default class App extends Component {
  state = {
    authed: false,
    loading: true
  }
  componentDidMount() {
    this.removeListener = firebaseAuth().onAuthStateChanged((user) => {
      if (user) {
        this.setState({ authed: true, loading: false })
      } else {
        this.setState({ authed: false, loading: false })
      }
    })
  }
  componentWillUnmount() {
    this.removeListener()
  }
  render() {
    return this.state.loading === true
      ?
Loading

      : (
        <BrowserRouter>

            <Navbar authed={this.state.authed} />

                <Switch>
                  <PublicRoute path='/' exact component={Home} />
                  <PublicRoute authed={this.state.authed} path='/login' component={Login} />
                  <PublicRoute authed={this.state.authed} path='/register' component={Register} />
                  <PrivateRoute authed={this.state.authed} path='/main' component={Main} />
                  <PrivateRoute authed={this.state.authed} path='/create' component={Create} />
                  <PrivateRoute authed={this.state.authed} path='/join' component={Join} />
                  <Route render={() =>
No Match
} />
                </Switch>

        </BrowserRouter>
      );
  }
}
<commit_msg>added M-UI<commit_after>import React, {Component} from 'react'
import {Route, BrowserRouter, Redirect, Switch} from 'react-router-dom'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import Login from './Login'
import Register from './Register'
import Home from './Home'
import Main from './protected/Main'
import Create from './protected/Create'
import Join from './protected/Join'
import {firebaseAuth} from '../config/constants'
import Navbar from './Navbar'

function PrivateRoute({
  component: Component,
  authed,
  ...rest
}) {
  return (
    <Route
      {...rest}
      render={(props) => authed === true
      ? <Component {...props}/>
      : <Redirect
        to={{
        pathname: '/login',
        state: {
          from: props.location
        }
      }}/>}/>
  )
}

function PublicRoute({
  component: Component,
  authed,
  ...rest
}) {
  return (
    <Route
      {...rest}
      render={(props) => authed === false
      ? <Component {...props}/>
      : <Redirect to='/main'/>}/>
  )
}

export default class App extends Component {
  state = {
    authed: false,
    loading: true
  }
  componentDidMount() {
    this.removeListener = firebaseAuth().onAuthStateChanged((user) => {
      if (user) {
        this.setState({authed: true, loading: false})
      } else {
        this.setState({authed: false, loading: false})
      }
    })
  }
  componentWillUnmount() {
    this.removeListener()
  }
  render() {
    return this.state.loading === true
      ?
Loading

      : (
        <MuiThemeProvider>
          <BrowserRouter>

              <Navbar authed={this.state.authed}/>

                  <Switch>
                    <PublicRoute path='/' exact component={Home}/>
                    <PublicRoute authed={this.state.authed} path='/login' component={Login}/>
                    <PublicRoute authed={this.state.authed} path='/register' component={Register}/>
                    <PrivateRoute authed={this.state.authed} path='/main' component={Main}/>
                    <PrivateRoute authed={this.state.authed} path='/create' component={Create}/>
                    <PrivateRoute authed={this.state.authed} path='/join' component={Join}/>
                    <Route render={() =>
No Match
}/>
                  </Switch>

          </BrowserRouter>
        </MuiThemeProvider>
      );
  }
}
<|endoftext|>


<commit_before>var debug = require('../utils/debug');
var diff = require('../utils').diff;
var registerComponent = require('../core/component').registerComponent;
var THREE = require('../lib/three');

var warn = debug('components:sound:warn');

/**
 * Sound component.
 *
 * @param {bool} [autoplay=false]
 * @param {string} on
 * @param {bool} [loop=false]
 * @param {number} [volume=1]
 */
module.exports.Component = registerComponent('sound', {
  schema: {
    src: { default: '' },
    on: { default: 'click' },
    autoplay: { default: false },
    loop: { default: false },
    volume: { default: 1 }
  },

  init: function () {
    this.listener = null;
    this.sound = null;
  },

  update: function (oldData) {
    var data = this.data;
    var diffData = diff(oldData || {}, data);
    var el = this.el;
    var sound = this.sound;
    var src = data.src;
    var srcChanged = 'src' in diffData;

    // Create new sound if not yet created or changing `src`.
    if (srcChanged) {
      if (!src) {
        warn('Audio source was not specified with `src`');
        return;
      }
      sound = this.setupSound();
    }

    if (srcChanged || 'autoplay' in diffData) {
      sound.autoplay = data.autoplay;
    }

    if (srcChanged || 'loop' in diffData) {
      sound.setLoop(data.loop);
    }

    if (srcChanged || 'volume' in diffData) {
      sound.setVolume(data.volume);
    }

    if ('on' in diffData) {
      if (oldData && oldData.on) {
        el.removeEventListener(oldData.on);
      }
      el.addEventListener(data.on, this.play.bind(this));
    }

    // All sound values set. Load in `src.
    if (srcChanged) {
      sound.load(src);
    }
  },

  remove: function () {
    this.el.removeObject3D('sound');
    this.sound.disconnect();
  },

  /**
   * Removes current sound object, creates new sound object, adds to entity.
   *
   * @returns {object} sound
   */
  setupSound: function () {
    var el = this.el;
    var sceneEl = el.sceneEl;
    var sound = this.sound;

    // we want to make sure we have exactly one AudioListener. Let's stick it somewhere
    // that's available to the next sound component that might get initialized
    var listener = this.listener = sceneEl.audioListener || new THREE.AudioListener();
    sceneEl.audioListener = listener;

    if (sound) {
      this.stop();
      el.removeObject3D('sound');
    }

    function addListenerToCamera() {
      sceneEl.camera.add(listener);
    }

    if (sceneEl.camera) {
      addListenerToCamera();
    } else {
      // if this el precedes the camera in the DOM, we won't have a camera yet.
      sceneEl.addEventListener('camera-ready', addListenerToCamera);
    }

    sound = this.sound = new THREE.PositionalAudio(listener);
    el.setObject3D('sound', sound);
    return sound;
  },

  play: function () {
    if (this.sound.source.buffer) {
      this.sound.play();
    }
  },

  stop: function () {
    this.sound.stop();
  },

  pause: function () {
    this.sound.pause();
  }
});
<commit_msg>fix lint<commit_after>var debug = require('../utils/debug');
var diff = require('../utils').diff;
var registerComponent = require('../core/component').registerComponent;
var THREE = require('../lib/three');

var warn = debug('components:sound:warn');

/**
 * Sound component.
 *
 * @param {bool} [autoplay=false]
 * @param {string} on
 * @param {bool} [loop=false]
 * @param {number} [volume=1]
 */
module.exports.Component = registerComponent('sound', {
  schema: {
    src: { default: '' },
    on: { default: 'click' },
    autoplay: { default: false },
    loop: { default: false },
    volume: { default: 1 }
  },

  init: function () {
    this.listener = null;
    this.sound = null;
  },

  update: function (oldData) {
    var data = this.data;
    var diffData = diff(oldData || {}, data);
    var el = this.el;
    var sound = this.sound;
    var src = data.src;
    var srcChanged = 'src' in diffData;

    // Create new sound if not yet created or changing `src`.
    if (srcChanged) {
      if (!src) {
        warn('Audio source was not specified with `src`');
        return;
      }
      sound = this.setupSound();
    }

    if (srcChanged || 'autoplay' in diffData) {
      sound.autoplay = data.autoplay;
    }

    if (srcChanged || 'loop' in diffData) {
      sound.setLoop(data.loop);
    }

    if (srcChanged || 'volume' in diffData) {
      sound.setVolume(data.volume);
    }

    if ('on' in diffData) {
      if (oldData && oldData.on) {
        el.removeEventListener(oldData.on);
      }
      el.addEventListener(data.on, this.play.bind(this));
    }

    // All sound values set. Load in `src.
    if (srcChanged) {
      sound.load(src);
    }
  },

  remove: function () {
    this.el.removeObject3D('sound');
    this.sound.disconnect();
  },

  /**
   * Removes current sound object, creates new sound object, adds to entity.
   *
   * @returns {object} sound
   */
  setupSound: function () {
    var el = this.el;
    var sceneEl = el.sceneEl;
    var sound = this.sound;

    if (sound) {
      this.stop();
      el.removeObject3D('sound');
    }

    // we want to make sure we have exactly one AudioListener. Let's stick it somewhere
    // that's available to the next sound component that might get initialized
    var listener = this.listener = sceneEl.audioListener || new THREE.AudioListener();
    sceneEl.audioListener = listener;

    function addListenerToCamera () {
      sceneEl.camera.add(listener);
    }

    if (sceneEl.camera) {
      addListenerToCamera();
    } else {
      // if this el precedes the camera in the DOM, we won't have a camera yet.
      sceneEl.addEventListener('camera-ready', addListenerToCamera);
    }

    sound = this.sound = new THREE.PositionalAudio(listener);
    el.setObject3D('sound', sound);
    return sound;
  },

  play: function () {
    if (this.sound.source.buffer) {
      this.sound.play();
    }
  },

  stop: function () {
    this.sound.stop();
  },

  pause: function () {
    this.sound.pause();
  }
});
<|endoftext|>