<commit_before>/**
 * Main module for analyze view
 * @param {type} $ jQuery module
 * @param {type} facebook Facebook Graph API module
 * @param {type} LastFMProxy LastFM API Wrapper module
 * @param {type} Aggregate Custom aggregation methods module
 * @returns {void}
 */
define (['jquery', 'facebook', 'LastFMProxy', 'StatsAnalyzer', 'SweetAlert'], function ($, facebook, LastFMProxy, StatsAnalyzer, SweetAlert) {

    // Stats object for every artist (associative array)
    var artistStats = [];

    // Stats for every friend who already used the app
    var friendStats = [];

    // Number of artists liked by the user
    var artistCount = 0;

    // Number of artist already analyzed
    var analyzedArtistCount = 0;

    /**
     * Try to login and get an array of musicians
     * @param {type} callback
     * @returns {undefined}
     */
    function getArtists(callback) {

        // Try to login after init is complete
        FB.getLoginStatus(function(response){
            FB.login(function () {
                FB.api(
                    "/me/music?fields=likes,id,name, category",
                    function (response) {
                          var likes = response.data || [];
                          var artists = [];

                          // Filter by  category
                          likes.forEach(function (like) {
                              if(like.category === "Musician/band") {
                                  artists.push(like);
                              }
                          });

                          callback(artists);

                });
            }, {scope: 'user_likes'});
        });

    }

    /**
     * Show the modal window with a given text
     * @param {type} title Window title to show
     * @param {type} text Text to show
     * @param {function} callback
     * @param {boolean} success
     * @returns {undefined}
     */
    function showModal (title, text, callback, success) {

        success = success || false;

        if (success) {
            SweetAlert({
                title: title,
                text: text,
                type: 'success'
            }, callback);
        } else {
            SweetAlert({
                title: title,
                text: text
            }, callback);
        }
    }

    /**
     * Update progress bar as analyzedArtistCound increases
     * @returns {undefined}
     */
    function updateProgress () {
        analyzedArtistCount++;
        var percent = analyzedArtistCount / artistCount;
        var progress = percent*100;
        $('#appProgress').css('width', progress + '%');
    }

    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function artistCallback (artist) {
        var initialStatus = $('#initial-status').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }
    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function albumCallback (artist) {
         var initialStatus = $('#initial-status-album').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }
    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function fanCallback (artist) {
        var initialStatus = $('#initial-status-fan').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }
    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function tagCallback (artist) {
        var initialStatus = $('#initial-status-tag').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }
    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function similarCallback (artist) {
        var initialStatus = $('#initial-status-similar').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    /**
     * Get stats one by one recursively and call a callback when finished
     * @param {array} artists
     * @param {function} callback
     * @returns {void}
     */
    function getStats (artists, callback) {

        // Race end: empty array
        if (artists.length === 0) {
            callback();
            return;
        }

        // Pop an artist from array
        var artist = artists.pop();

        // Get stats for the popped artist and then continue
        LastFMProxy.getStats(artist.id, artist.name, artistCallback, albumCallback, fanCallback, tagCallback, similarCallback, function (stats) {
            updateProgress();
            artistStats[artist.name] = JSON.parse(stats);
            getStats(artists, callback);

        });
    }

    /**
     * Fill and show the results template
     * @returns {void}
     */
    function showResults() {

        // Analyze the stats
        StatsAnalyzer.build(artistStats);

        // Get the results text
        var ageText = StatsAnalyzer.getAgeText();
        var epochText = StatsAnalyzer.getEpochText();
        var styleText = StatsAnalyzer.getStyleText();
        var similarText = StatsAnalyzer.getSimilarText();

        // Print the resutls
        $('#age_result').text(ageText);
        $('#epoch_result').text(epochText);
        $('#style_result').text(styleText);
        $('#similar_result').text(similarText);

        // Add sharing event handlers shareResult('prueba');
        $('#share_age').click(function () { shareResult(ageText); });
        $('#share_epoch').click(function () { shareResult(epochText); });
        $('#share_style').click(function () { shareResult(styleText); });
        $('#share_similar').click(function () { shareResult(similarText); });

        // Ad "How does it work?" links
        $('#howAge').click(function () {
            showModal($('#how-button').val(), $('#how-age').val());
        });
        $('#howStyle').click(function () {
            showModal($('#how-button').val(), $('#how-style').val());
        });
        $('#howEpoch').click(function () {
            showModal($('#how-button').val(), $('#how-epoch').val());
        });
        $('#howSimilar').click(function () {
            showModal($('#how-button').val(), $('#how-similar').val());
        });

        $('#process').hide();
        $('#results').removeClass('hidden');
        $('#results').animate({
            maxHeight: '1000000px',
            opacity:1
        },{
            duration: 1000
        });

        loadLikesChart();

    }

    function loadLikesChart () {
        $(function () {
            $('#likesChart').highcharts({
                    chart: {
                        type: 'bar',
                        backgroundColor: '#eee'
                    },
                    title: {
                        text: 'Likes musicales'
                    },
                    xAxis: {
                        categories: ['Javier Polo Picasso', 'Gerardo Castaño Recuero', 'Isabel Valdesquer']
                    },
                    yAxis: {
                    },
                    series: [{
                        name: 'Número de likes',
                        data: [10, 15, 63],
                        color: '#337ab7'
                    }]
            });
        });
    }

    /**
     * Select the n artits with the most likes
     * @param {type} artists
     * @param {type} n
     * @returns {@exp;artists@call;splice}
     */
    function selectTopRated (artists, n) {
        // Sort from more to less likes
        artists.sort(function (a, b) {
            return b.likes - a.likes;
        });
        return artists.splice(0,n);
    }

    /**
     * Share a result to the Facebook timeline
     * @param {type} message
     * @returns {undefined}
     */
    function shareResult (message) {
        var wallPost = {
            method: 'feed',
            picture: $('#share-image').val(),
            link: 'https://apps.facebook.com/music-analyzer',
            name: message,
            caption: "music-analyzer.herokuapp.com",
            description: $('#description').val()
        };
        FB.ui(wallPost);
    }

    /**
     * Start the analysis
     * @returns {undefined}
     */
    function startAnalyzing () {

        // Set title
        $('#title').text($('#analyze-title').val());

        // Get user artists
        getArtists(function (artists) {

            var MAX_ARTISTS = 10;

            // If no artist likes show message
            if (artists.length === 0) {
                showModal($('#error-title').val(), $('#error-status').val(), function () {
                    document.location = '/';
                });
            }
            // If too much musicians  select the top 10 sorting by likes count
            if (artists.length > MAX_ARTISTS) {
                artists = selectTopRated(artists, MAX_ARTISTS);
            }

            artistCount = artists.length || 0;

            // Else get stats one by one
            getStats(artists, function () {
                showResults();
            });

        });
    }

    /**
     * PUBLIC INTERFACE
     */
    return {
        startAnalyzing: startAnalyzing
    };

}); // End module<commit_msg>Eliminado link publicitario de HighCharts<commit_after>/**
 * Main module for analyze view
 * @param {type} $ jQuery module
 * @param {type} facebook Facebook Graph API module
 * @param {type} LastFMProxy LastFM API Wrapper module
 * @param {type} Aggregate Custom aggregation methods module
 * @returns {void}
 */
define (['jquery', 'facebook', 'LastFMProxy', 'StatsAnalyzer', 'SweetAlert'], function ($, facebook, LastFMProxy, StatsAnalyzer, SweetAlert) {

    // Stats object for every artist (associative array)
    var artistStats = [];

    // Stats for every friend who already used the app
    var friendStats = [];

    // Number of artists liked by the user
    var artistCount = 0;

    // Number of artist already analyzed
    var analyzedArtistCount = 0;

    /**
     * Try to login and get an array of musicians
     * @param {type} callback
     * @returns {undefined}
     */
    function getArtists(callback) {

        // Try to login after init is complete
        FB.getLoginStatus(function(response){
            FB.login(function () {
                FB.api(
                    "/me/music?fields=likes,id,name, category",
                    function (response) {
                          var likes = response.data || [];
                          var artists = [];

                          // Filter by  category
                          likes.forEach(function (like) {
                              if(like.category === "Musician/band") {
                                  artists.push(like);
                              }
                          });

                          callback(artists);

                });
            }, {scope: 'user_likes'});
        });

    }

    /**
     * Show the modal window with a given text
     * @param {type} title Window title to show
     * @param {type} text Text to show
     * @param {function} callback
     * @param {boolean} success
     * @returns {undefined}
     */
    function showModal (title, text, callback, success) {

        success = success || false;

        if (success) {
            SweetAlert({
                title: title,
                text: text,
                type: 'success'
            }, callback);
        } else {
            SweetAlert({
                title: title,
                text: text
            }, callback);
        }
    }

    /**
     * Update progress bar as analyzedArtistCound increases
     * @returns {undefined}
     */
    function updateProgress () {
        analyzedArtistCount++;
        var percent = analyzedArtistCount / artistCount;
        var progress = percent*100;
        $('#appProgress').css('width', progress + '%');
    }

    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function artistCallback (artist) {
        var initialStatus = $('#initial-status').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }
    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function albumCallback (artist) {
         var initialStatus = $('#initial-status-album').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }
    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function fanCallback (artist) {
        var initialStatus = $('#initial-status-fan').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }
    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function tagCallback (artist) {
        var initialStatus = $('#initial-status-tag').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }
    /**
     * Callback for showing status
     * @param {type} artist
     * @returns {undefined}
     */
    function similarCallback (artist) {
        var initialStatus = $('#initial-status-similar').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    /**
     * Get stats one by one recursively and call a callback when finished
     * @param {array} artists
     * @param {function} callback
     * @returns {void}
     */
    function getStats (artists, callback) {

        // Race end: empty array
        if (artists.length === 0) {
            callback();
            return;
        }

        // Pop an artist from array
        var artist = artists.pop();

        // Get stats for the popped artist and then continue
        LastFMProxy.getStats(artist.id, artist.name, artistCallback, albumCallback, fanCallback, tagCallback, similarCallback, function (stats) {
            updateProgress();
            artistStats[artist.name] = JSON.parse(stats);
            getStats(artists, callback);

        });
    }

    /**
     * Fill and show the results template
     * @returns {void}
     */
    function showResults() {

        // Analyze the stats
        StatsAnalyzer.build(artistStats);

        // Get the results text
        var ageText = StatsAnalyzer.getAgeText();
        var epochText = StatsAnalyzer.getEpochText();
        var styleText = StatsAnalyzer.getStyleText();
        var similarText = StatsAnalyzer.getSimilarText();

        // Print the resutls
        $('#age_result').text(ageText);
        $('#epoch_result').text(epochText);
        $('#style_result').text(styleText);
        $('#similar_result').text(similarText);

        // Add sharing event handlers shareResult('prueba');
        $('#share_age').click(function () { shareResult(ageText); });
        $('#share_epoch').click(function () { shareResult(epochText); });
        $('#share_style').click(function () { shareResult(styleText); });
        $('#share_similar').click(function () { shareResult(similarText); });

        // Ad "How does it work?" links
        $('#howAge').click(function () {
            showModal($('#how-button').val(), $('#how-age').val());
        });
        $('#howStyle').click(function () {
            showModal($('#how-button').val(), $('#how-style').val());
        });
        $('#howEpoch').click(function () {
            showModal($('#how-button').val(), $('#how-epoch').val());
        });
        $('#howSimilar').click(function () {
            showModal($('#how-button').val(), $('#how-similar').val());
        });

        $('#process').hide();
        $('#results').removeClass('hidden');
        $('#results').animate({
            maxHeight: '1000000px',
            opacity:1
        },{
            duration: 1000
        });

        loadLikesChart();

    }

    function loadLikesChart () {
        $(function () {
            $('#likesChart').highcharts({
                    credits: false,
                    chart: {
                        type: 'bar',
                        backgroundColor: '#eee'
                    },
                    title: {
                        text: 'Likes musicales'
                    },
                    xAxis: {
                        categories: ['Javier Polo Picasso', 'Gerardo Castaño Recuero', 'Isabel Valdesquer']
                    },
                    yAxis: {
                    },
                    series: [{
                        name: 'Número de likes',
                        data: [10, 15, 63],
                        color: '#337ab7'
                    }]
            });
        });
    }

    /**
     * Select the n artits with the most likes
     * @param {type} artists
     * @param {type} n
     * @returns {@exp;artists@call;splice}
     */
    function selectTopRated (artists, n) {
        // Sort from more to less likes
        artists.sort(function (a, b) {
            return b.likes - a.likes;
        });
        return artists.splice(0,n);
    }

    /**
     * Share a result to the Facebook timeline
     * @param {type} message
     * @returns {undefined}
     */
    function shareResult (message) {
        var wallPost = {
            method: 'feed',
            picture: $('#share-image').val(),
            link: 'https://apps.facebook.com/music-analyzer',
            name: message,
            caption: "music-analyzer.herokuapp.com",
            description: $('#description').val()
        };
        FB.ui(wallPost);
    }

    /**
     * Start the analysis
     * @returns {undefined}
     */
    function startAnalyzing () {

        // Set title
        $('#title').text($('#analyze-title').val());

        // Get user artists
        getArtists(function (artists) {

            var MAX_ARTISTS = 10;

            // If no artist likes show message
            if (artists.length === 0) {
                showModal($('#error-title').val(), $('#error-status').val(), function () {
                    document.location = '/';
                });
            }
            // If too much musicians  select the top 10 sorting by likes count
            if (artists.length > MAX_ARTISTS) {
                artists = selectTopRated(artists, MAX_ARTISTS);
            }

            artistCount = artists.length || 0;

            // Else get stats one by one
            getStats(artists, function () {
                showResults();
            });

        });
    }

    /**
     * PUBLIC INTERFACE
     */
    return {
        startAnalyzing: startAnalyzing
    };

}); // End module<|endoftext|>


<commit_before>(function ($) {

    $.fn.bigmenu = function (options) {

        var self = this;
        var settings = $.extend({
            widthToEnableResponsive: 768
        }, options);

        /* Pages are stored here instead loading again */
        var contentBuffer = {};

        /* Main selector for dynamic loaded content */
        var pageBoxSelector = ".bigmenu-page-panel";

        var resize = function (e) {
            var o = $(self).closest('.bigmenu');
            if (window.innerWidth >= settings.widthToEnableResponsive) {
                o.removeClass('responsive');
            } else {
                o.addClass('responsive');
            }
        };
        var bigmenu = {
            loadContent: function (o) {
                self.resize();
                if (window.innerWidth >= settings.widthToEnableResponsive) {
                    this._load(o);
                }
            },
            _load: function (o) {
                var pageToLoad = o.data('bigmenu-page');
                o.hoverIntent(function () {
                    if (typeof contentBuffer[pageToLoad] != "string") {
                        $.ajax({
                            method: "GET",
                            url: pageToLoad,
                            beforeSend: function () {
                                /* todo: Replace with a css loading animation*/
                                //pageTarget.html("Loading");
                            }
                        }).done(function (data, textStatus, jqXHR) {
                            if (data) {
                                contentBuffer[pageToLoad] = data;
                                pageTarget.html(data).addClass('opened');
                            }

                        }).fail(function (data, textStatus, jqXHR) {
                            if (console) {
                                console.error("Bigmenu could not load page.", textStatus);
                            }

                        })

                    } else {
                        pageTarget.html(contentBuffer[pageToLoad]).addClass('opened')
                    }

                }, function () {
                    pageTarget.removeClass("opened");
                    /* hoverOut */
                })

            }
        };

        var pageTarget = $(pageBoxSelector);

        $(window).resize(function(){
            resize();
        })
        return this.each(function () {
            /* hoverIn */
            var o = $(this);
            bigmenu.loadContent(o);
        })

    };

}(jQuery));

$(".bigmenu-ajax").bigmenu(YII2_BIGMENU_WIDGET_OPTIONS);
<commit_msg>Tag 1.3<commit_after>(function ($) {

    $.fn.bigmenu = function (options) {

        var self = this;
        var settings = $.extend({
            widthToEnableResponsive: 768
        }, options);
        /* Pages are stored here instead loading again */
        var contentBuffer = {};

        /* Main selector for dynamic loaded content */
        var pageBoxSelector = ".bigmenu-page-panel";

        var bigmenu = {
            resize: function (e) {
                var o = $(self).closest('.bigmenu');
                if (window.innerWidth >= settings.widthToEnableResponsive) {
                    o.removeClass('responsive');
                } else {
                    o.addClass('responsive');
                }
            }, loadContent: function (o) {
                this.resize();
                if (window.innerWidth >= settings.widthToEnableResponsive) {
                    this._load(o);
                }
            }, _load: function (o) {
                var pageToLoad = o.data('bigmenu-page');
                o.hoverIntent(function () {
                    if (typeof contentBuffer[pageToLoad] != "string") {
                        $.ajax({
                            method: "GET", url: pageToLoad, beforeSend: function () {
                                /* todo: Replace with a css loading animation*/
                                //pageTarget.html("Loading");
                            }
                        }).done(function (data, textStatus, jqXHR) {
                            if (data) {
                                contentBuffer[pageToLoad] = data;
                                pageTarget.html(data).addClass('opened');
                            }

                        }).fail(function (data, textStatus, jqXHR) {
                            if (console) {
                                console.error("Bigmenu could not load page.", textStatus);
                            }

                        })

                    } else {
                        pageTarget.html(contentBuffer[pageToLoad]).addClass('opened')
                    }

                }, function () {
                    pageTarget.removeClass("opened");
                    /* hoverOut */
                })

            }
        };

        var pageTarget = $(pageBoxSelector);
        $(window).resize(function () {
            self.each(function () {
                var o = $(this);
                bigmenu.resize(o);
            });
        })
        return self.each(function () {
            var o = $(this);
            bigmenu.resize(o);
            var ajaxEls = o.find('.bigmenu-ajax');
            ajaxEls.each(function () {
                /* hoverIn */
                var ajaxEl = $(this);
                bigmenu.loadContent(ajaxEl);
            });
        });
    };
}(jQuery));
$(".bigmenu").bigmenu(YII2_BIGMENU_WIDGET_OPTIONS);
<|endoftext|>


<commit_before>$(document).ready(getposts);
function getposts(){

    $.getJSON('entries.json', function(data) {
		$.each(data.entries.reverse(), function(key, val) {
                var output="
";
				    output+="
" + val.date +"
";
				    output+="
" + val.title +"
";
				    output+="
" + val.text +"
";
				    output+="
";
					output+="
";

				$("#blog").append(output);
				$('#blog').paginate({itemsPerPage: 2});
      	});
    });
}

$('#search2').keyup(function () {
    var searchField = $('#search2').val();
    if (searchField.length){
    var myExp = new RegExp(searchField, "i");
    var found = 0;

   $.getJSON('entries.json', function (data) {
   var output = '
';

   $.each(data.entries, function(key, val) {
      if (val.text.search(myExp) !== -1 || val.title.search(myExp) !== -1) {
      console.log(val);
      found = 1;
      output += '
';
      output += '
';
      output += '
' + val.date + '
';
      output += '
' + val.title + '
';
      output += '
' + val.text + '
';
      output += '
';
      }
   });
      output += '
';

      output += '
';
	  output += '« Newer';
	  output += ' | ';
	  output += 'Older »';
      output += '
';
      output += '
';
      output += 'hello';
      output += '
'

      if (found==1) {
      $('#update').removeClass('update-hidden');
      $('#update').html(output);
      $('#searchresults').paginate({itemsPerPage: 4});
      }
      else {
          $('#update').addClass('update-hidden');
      }

});
    } else {
      $('#update').addClass('update-hidden');
    }
});
<commit_msg>Last again<commit_after>$(document).ready(getposts);
function getposts(){

    $.getJSON('entries.json', function(data) {
		$.each(data.entries.reverse(), function(key, val) {
                var output="
";
				    output+="
" + val.date +"
";
				    output+="
" + val.title +"
";
				    output+="
" + val.text +"
";
				    output+="
";
					output+="
";

				$("#blog").append(output);
				$('#blog').paginate({itemsPerPage: 2});
      	});
    });
}

$('#search2').keyup(function () {
    var searchField = $('#search2').val();
    if (searchField.length){
    var myExp = new RegExp(searchField, "i");
    var found = 0;

   $.getJSON('entries.json', function (data) {
   var output = '
';

   $.each(data.entries, function(key, val) {
      if (val.text.search(myExp) !== -1 || val.title.search(myExp) !== -1) {
      console.log(val);
      found = 1;
      output += '
';
      output += '
';
      output += '
' + val.date + '
';
      output += '
' + val.title + '
';
      output += '
' + val.text + '
';
      output += '
';
      }
   });
      output += '
';

      output += '
';
	  output += '« Newer';
	  output += ' | ';
	  output += 'Older »';
      output += '
';
      output += '
';
      output += '
';
      output += '
'

      if (found==1) {
      $('#update').removeClass('update-hidden');
      $('#update').html(output);
      $('#searchresults').paginate({itemsPerPage: 4});
      }
      else {
          $('#update').addClass('update-hidden');
      }

});
    } else {
      $('#update').addClass('update-hidden');
    }
});
<|endoftext|>


<commit_before>$(function(){
	// I hate the chromeless player, i'll never build my own controls. Take this dummy!
	swfobject.embedSWF("http://www.youtube.com/v/xxxxxxxxxxx?enablejsapi=1&playerapiid=ytplayer&version=3&autohide=1&theme=light", "replace-player", "100%", "380", "8", null, null, { allowScriptAccess: "always" }, { id: "myytplayer" });
	$('._tt').tooltip({placement:'bottom'});
	$('#itemURL').keyup(function(){
		var reg = $('#itemURL').val().match(/(?:youtube(?:-nocookie)?\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/);
		if(reg){
			var tag = document.createElement('script');
			tag.src = "https://gdata.youtube.com/feeds/api/videos/" + reg[1] + "?alt=json-in-script&v=2&callback=gdataCallbackProxy";
			var firstScriptTag = document.getElementsByTagName('script')[0];
			firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
		} else {
			angular.element('html').scope().add_item.valid = false;
			angular.element('html').scope().$apply();
		}
	});
	$('.channel-cover-text').dotdotdot({watch:true});
});
var app = angular.module('channel',[]);
var socket = io.connect('//' + window.location.host + ':8080', { query:"session_id=" + readCookie("session_id") + "&channel_id=" + channel_id });
var player;

function gdataCallbackProxy(data){angular.element('html').scope().gdataCallback(data);}
function stateChangeProxy(state){angular.element('html').scope().playerStateChange(state);}
function onYouTubePlayerReady(playerId) {
	player = document.getElementById("myytplayer");
	player.addEventListener("onStateChange", "stateChangeProxy");
	socket.emit('channel.init');
}

function channel_controller($scope){
	$scope.playlist = [];
	$scope.chat = [];
	$scope.online = [];
	$scope.alert_stack = [];
	$scope.add_item = { valid: false };
	$scope.login_name = "";
	$scope.display_name = "";
	$scope.views = 0;
	$scope.favs = 0;
	// The currently active media-item-_id
	$scope.active_item = 1;
	$scope.reordered = false;
	$scope.removed = false;

	socket.on('channel.init', function(data){
		$scope.playlist = data.content.playlist;
		$scope.chat = data.content.last_chat;
		$scope.online = data.content.users_online;
		$scope.favs = data.content.favourites;
		$scope.views = data.content.views;
		$scope.active_item = data.content.now_playing._id;
		$scope.logged_in = true;

		$scope.is_admin = data.content.user_data.is_admin;
		$scope.login_name = data.content.user_data.login_name;
		$scope.display_name = data.content.user_data.display_name;

		$scope.show_add = false;

		var start_seconds = (new Date().getTime() - new Date(data.content.now_playing.start_time).getTime()) / 1000;
		player.loadVideoById(data.content.now_playing.url, start_seconds);
		$scope.$apply();
		$('.channel-chat > ul').scrollTop($('.channel-chat > ul')[0].scrollHeight);
	});
	socket.on('playlist.append_item', function(data){
		$scope.playlist.push(data.content);
		$scope.$apply();
	});
	socket.on('playlist.play_item', function(data){
		var start_seconds = (new Date().getTime() - new Date(data.content.start_time).getTime()) / 1000;
		var item;
		for (var i = 0; i < $scope.playlist.length; i++) {
			if($scope.playlist[i]._id === data.content._id){
				item = $scope.playlist[i];
				break;
			}
		};
		player.loadVideoById(item.url, start_seconds);
		$scope.active_item = item._id;
		$scope.$apply();
	});
	socket.on('playlist.reorder', function(data){
		// may we get this a little more efficient?
		for (var x = 0; x < $scope.playlist.length; x++) {
			for (var y = 0; y < data.content.length; y++) {
				if($scope.playlist[x]._id === data.content[y]._id)
					$scope.playlist[x].position = data.content[y].position;
			};
		};
		$scope.$apply();
	});
	socket.on('chat.incoming', function(data){
		$scope.chat.push(data.content);
		$scope.$apply();
		$('.channel-chat > ul').animate({ scrollTop: $('.channel-chat > ul')[0].scrollHeight},800);
	});
	socket.on('channel.user_join', function(data){
		$scope.online.push(data.content);
		$scope.$apply();
	});
	socket.on('channel.user_leave', function(data){
		for (var i = 0; i < $scope.online.length; i++) {
			if($scope.online[i].user_id === data.content._id){
				$scope.online.splice(i, 1);
				break;
			}
		};
		$scope.$apply();
	});
	socket.socket.on('error', function(data){
		$scope.alert_stack.push({ status: "-1", content: {code: "Unable to connect to Synergy-Server"}});
		$scope.$apply();
	});
	socket.on('error', function(data){
		$scope.alert_stack.push(data);
		$scope.$apply();
	});
	socket.on('user.session_id', function(data){
		createCookie("session_id", data.content.session_id);
		window.location.reload();
		//socket = io.connect('//' + window.location.host + ':8080', { query:"session_id=" + data.content.session_id + "&channel_id=" + channel_id });
	});
	socket.on('user.destroy_session', function(){
		eraseCookie("session_id");
		window.location.reload();
		//socket = io.connect('//' + window.location.host + ':8080', { query:"session_id=0&channel_id=" + channel_id });
	});

	$scope.login = function(){
		socket.emit('user.login', { login_name: $scope.login_name, password: $scope.password  });
		$scope.password = "";
		$scope.login_name = "";
	}
	$scope.logout = function(){
		socket.emit('user.logout');
	}
	$scope.create_account = function() {
		socket.emit('user.create_account', { login_name: $scope.create_login_name, email: $scope.email, password: $scope.create_password });
		$scope.create_login_name = "";
		$scope.email = "";
		$scope.create_password = "";
	}
	$scope.sendMessage = function(){
		if($scope.message)
			socket.emit('chat.send', { content: $scope.message });
		$scope.message = '';
	};

	$scope.dismiss_alert = function(alert){
		$scope.alert_stack.splice($scope.alert_stack.indexOf(alert), 1);
	};

	$scope.getTime = function(t){
		t = new Date(t);
		return (t.getHours() < 10 ? '0' : '') + t.getHours() + ":" + (t.getMinutes() < 10 ? '0' : '') + t.getMinutes();
	};
	$scope.getLength = function(s){
		s = new Date(s * 1000);
		return (s.getMinutes() < 10 ? '0' : '') + s.getMinutes() + ":" + (s.getSeconds() < 10 ? '0' : '') + s.getSeconds();
	};
	$scope.getPermLevel = function(lvl){
		// some glitter for the admins
		if(lvl === 1)
			return '';
		if(lvl === 2)
			return '
';
		else
			return '';
	};

	$scope.playerStateChange = function(state){
		if(state === 0){
			console.log("Media_Item ended");
			$scope.playNext();
		}
	};
	$scope.playNext = function() {
		var pos = -1;
		var next_item = null;
		// This'll be a torture!
		for (var i = 0; i < $scope.playlist.length; i++) {
			if($scope.playlist[i]._id === $scope.active_item)
				pos = $scope.playlist[i].position;
			if(pos !== -1)
				if($scope.playlist[i].position === pos + 1)
					next_item = $scope.playlist[i];
		}
		if(next_item === null)
			for (var i = 0; i < $scope.playlist.length; i++)
				if($scope.playlist[i].position === pos + 1)
					next_item = $scope.playlist[i];
		if(next_item === null)
			for (var i = 0; i < $scope.playlist.length; i++)
				if($scope.playlist[i].position === 1)
					next_item = $scope.playlist[i];

		console.log("Old pos: " + pos + " New pos: " + next_item.position);
		$scope.active_item = next_item._id;
		$scope.$apply();
		player.loadVideoById(next_item.url);
		socket.emit('playlist.item_changed', { _id: $scope.active_item, caption: next_item.caption });
	};
	$scope.play_item = function(item_id){
		var item;
		for (var i = 0; i < $scope.playlist.length; i++) {
			if($scope.playlist[i]._id === item_id)
				item = $scope.playlist[i];
		};
		player.loadVideoById(item.url);
		$scope.active_item = item._id;
		socket.emit('playlist.play_item', { _id: item_id, start_time: new Date() });
	};
	$scope.add_item = function(){
		$scope.show_add = false;
		$scope.add_item = { valid:false };
		$scope.itemURL = "";
		socket.emit('playlist.append_item', { url:$scope.add_item.url, duration:$scope.add_item.duration, caption:$scope.add_item.caption, media_type: $scope.add_item.media_type});
	};
	$scope.remove_item = function(item_id){
		for (var i = 0; i < $scope.playlist.length; i++) {
			if($scope.playlist[i]._id === item_id){
				$scope.playlist.splice(i, 1);
				break;
			}
		};
		$scope.removed = true;
		for(var i = 0; i < $scope.playlist.length; i++){
			$scope.playlist[i].position = i + 1;
		}
		socket.emit('playlist.remove_item', { _id: item_id });
	}
	$scope.gdataCallback = function(data){
		if(data.entry) {
			$scope.add_item.url = data.entry.media$group.yt$videoid.$t;
			$scope.add_item.duration = data.entry.media$group.media$content[0].duration;
			$scope.add_item.caption = data.entry.title.$t;
			$scope.add_item.media_type = "youtube";
			$scope.add_item.valid = true;
		} else
			$scope.add_item.valid = false;
		$scope.$apply();
	};

	$scope.$watch("playlist", function(value){
		if($scope.reordered || $scope.removed){
			var r = value.map(function(e){ return { _id: e._id, position: e.position }; });
			socket.emit('playlist.reorder', r);
		}
	}, true);
}

app.directive('dndList', function(){
	return function(scope, element, attrs){
		var toUpdate;
		var startIndex = -1;

		scope.$watch(attrs.dndList, function(value){
			toUpdate = value;
		},true);

		$(element[0]).sortable({
			items:'tr',
			start: function(event, ui){
				startIndex = ($(ui.item).index());
				scope.reordered = true;
			},
			stop: function(event, ui){
				if(socket.is_admin) {
					console.log("Item: " + toUpdate[startIndex]._id + "; Old Position: " + toUpdate[startIndex].position + "; New Position: " + ($(ui.item).index() + 1));
					var newIndex = ($(ui.item).index());
					var toMove = toUpdate[startIndex];
					toUpdate.splice(startIndex, 1);
					toUpdate.splice(newIndex,0,toMove);
					for(var i = 0; i < scope.playlist.length; i++){
						scope.playlist[i].position = i + 1;
					}
				}
				scope.$apply(scope.playlist);
			},
			axis: 'y'
		});
	};
});
function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}
<commit_msg>that's not supposed to happen...<commit_after>$(function(){
	// I hate the chromeless player, i'll never build my own controls. Take this dummy!
	swfobject.embedSWF("http://www.youtube.com/v/xxxxxxxxxxx?enablejsapi=1&playerapiid=ytplayer&version=3&autohide=1&theme=light", "replace-player", "100%", "380", "8", null, null, { allowScriptAccess: "always" }, { id: "myytplayer" });
	$('._tt').tooltip({placement:'bottom'});
	$('#itemURL').keyup(function(){
		var reg = $('#itemURL').val().match(/(?:youtube(?:-nocookie)?\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/);
		if(reg){
			var tag = document.createElement('script');
			tag.src = "https://gdata.youtube.com/feeds/api/videos/" + reg[1] + "?alt=json-in-script&v=2&callback=gdataCallbackProxy";
			var firstScriptTag = document.getElementsByTagName('script')[0];
			firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
		} else {
			angular.element('html').scope().add_item.valid = false;
			angular.element('html').scope().$apply();
		}
	});
	$('.channel-cover-text').dotdotdot({watch:true});
});
var app = angular.module('channel',[]);
var socket = io.connect('//' + window.location.host + ':8080', { query:"session_id=" + readCookie("session_id") + "&channel_id=" + channel_id });
var player;

function gdataCallbackProxy(data){angular.element('html').scope().gdataCallback(data);}
function stateChangeProxy(state){angular.element('html').scope().playerStateChange(state);}
function onYouTubePlayerReady(playerId) {
	player = document.getElementById("myytplayer");
	player.addEventListener("onStateChange", "stateChangeProxy");
	socket.emit('channel.init');
}

function channel_controller($scope){
	$scope.playlist = [];
	$scope.chat = [];
	$scope.online = [];
	$scope.alert_stack = [];
	$scope.add_item = { valid: false };
	$scope.login_name = "";
	$scope.display_name = "";
	$scope.views = 0;
	$scope.favs = 0;
	// The currently active media-item-_id
	$scope.active_item = 1;
	$scope.reordered = false;
	$scope.removed = false;

	socket.on('channel.init', function(data){
		$scope.playlist = data.content.playlist;
		$scope.chat = data.content.last_chat;
		$scope.online = data.content.users_online;
		$scope.favs = data.content.favourites;
		$scope.views = data.content.views;
		$scope.active_item = data.content.now_playing._id;
		$scope.logged_in = true;

		$scope.is_admin = data.content.user_data.is_admin;
		$scope.login_name = data.content.user_data.login_name;
		$scope.display_name = data.content.user_data.display_name;

		$scope.show_add = false;

		var start_seconds = (new Date().getTime() - new Date(data.content.now_playing.start_time).getTime()) / 1000;
		player.loadVideoById(data.content.now_playing.url, start_seconds);
		$scope.$apply();
		$('.channel-chat > ul').scrollTop($('.channel-chat > ul')[0].scrollHeight);
	});
	socket.on('playlist.append_item', function(data){
		$scope.playlist.push(data.content);
		$scope.$apply();
	});
	socket.on('playlist.play_item', function(data){
		var start_seconds = (new Date().getTime() - new Date(data.content.start_time).getTime()) / 1000;
		var item;
		for (var i = 0; i < $scope.playlist.length; i++) {
			if($scope.playlist[i]._id === data.content._id){
				item = $scope.playlist[i];
				break;
			}
		};
		player.loadVideoById(item.url, start_seconds);
		$scope.active_item = item._id;
		$scope.$apply();
	});
	socket.on('playlist.reorder', function(data){
		// may we get this a little more efficient?
		for (var x = 0; x < $scope.playlist.length; x++) {
			for (var y = 0; y < data.content.length; y++) {
				if($scope.playlist[x]._id === data.content[y]._id)
					$scope.playlist[x].position = data.content[y].position;
			};
		};
		$scope.$apply();
	});
	socket.on('chat.incoming', function(data){
		$scope.chat.push(data.content);
		$scope.$apply();
		$('.channel-chat > ul').animate({ scrollTop: $('.channel-chat > ul')[0].scrollHeight},800);
	});
	socket.on('channel.user_join', function(data){
		$scope.online.push(data.content);
		$scope.$apply();
	});
	socket.on('channel.user_leave', function(data){
		for (var i = 0; i < $scope.online.length; i++) {
			if($scope.online[i].user_id === data.content._id){
				$scope.online.splice(i, 1);
				break;
			}
		};
		$scope.$apply();
	});
	socket.socket.on('error', function(data){
		$scope.alert_stack.push({ status: "-1", content: {code: "Unable to connect to Synergy-Server"}});
		$scope.$apply();
	});
	socket.on('error', function(data){
		$scope.alert_stack.push(data);
		$scope.$apply();
	});
	socket.on('user.session_id', function(data){
		createCookie("session_id", data.content.session_id);
		window.location.reload();
		//socket = io.connect('//' + window.location.host + ':8080', { query:"session_id=" + data.content.session_id + "&channel_id=" + channel_id });
	});
	socket.on('user.destroy_session', function(){
		eraseCookie("session_id");
		window.location.reload();
		//socket = io.connect('//' + window.location.host + ':8080', { query:"session_id=0&channel_id=" + channel_id });
	});

	$scope.login = function(){
		socket.emit('user.login', { login_name: $scope.login_name, password: $scope.password  });
		$scope.password = "";
		$scope.login_name = "";
	}
	$scope.logout = function(){
		socket.emit('user.logout');
	}
	$scope.create_account = function() {
		socket.emit('user.create_account', { login_name: $scope.create_login_name, email: $scope.email, password: $scope.create_password });
		$scope.create_login_name = "";
		$scope.email = "";
		$scope.create_password = "";
	}
	$scope.sendMessage = function(){
		if($scope.message)
			socket.emit('chat.send', { content: $scope.message });
		$scope.message = '';
	};

	$scope.dismiss_alert = function(alert){
		$scope.alert_stack.splice($scope.alert_stack.indexOf(alert), 1);
	};

	$scope.getTime = function(t){
		t = new Date(t);
		return (t.getHours() < 10 ? '0' : '') + t.getHours() + ":" + (t.getMinutes() < 10 ? '0' : '') + t.getMinutes();
	};
	$scope.getLength = function(s){
		s = new Date(s * 1000);
		return (s.getMinutes() < 10 ? '0' : '') + s.getMinutes() + ":" + (s.getSeconds() < 10 ? '0' : '') + s.getSeconds();
	};
	$scope.getPermLevel = function(lvl){
		// some glitter for the admins
		if(lvl === 1)
			return '';
		if(lvl === 2)
			return '
';
		else
			return '';
	};

	$scope.playerStateChange = function(state){
		if(state === 0){
			console.log("Media_Item ended");
			$scope.playNext();
		}
	};
	$scope.playNext = function() {
		var pos = -1;
		var next_item = null;
		// This'll be a torture!
		for (var i = 0; i < $scope.playlist.length; i++) {
			if($scope.playlist[i]._id === $scope.active_item)
				pos = $scope.playlist[i].position;
			if(pos !== -1)
				if($scope.playlist[i].position === pos + 1)
					next_item = $scope.playlist[i];
		}
		if(next_item === null)
			for (var i = 0; i < $scope.playlist.length; i++)
				if($scope.playlist[i].position === pos + 1)
					next_item = $scope.playlist[i];
		if(next_item === null)
			for (var i = 0; i < $scope.playlist.length; i++)
				if($scope.playlist[i].position === 1)
					next_item = $scope.playlist[i];

		console.log("Old pos: " + pos + " New pos: " + next_item.position);
		$scope.active_item = next_item._id;
		$scope.$apply();
		player.loadVideoById(next_item.url);
		socket.emit('playlist.item_changed', { _id: $scope.active_item, caption: next_item.caption });
	};
	$scope.play_item = function(item_id){
		var item;
		for (var i = 0; i < $scope.playlist.length; i++) {
			if($scope.playlist[i]._id === item_id)
				item = $scope.playlist[i];
		};
		player.loadVideoById(item.url);
		$scope.active_item = item._id;
		socket.emit('playlist.play_item', { _id: item_id, start_time: new Date() });
	};
	$scope.add_item = function(){
		socket.emit('playlist.append_item', { url:$scope.add_item.url, duration:$scope.add_item.duration, caption:$scope.add_item.caption, media_type: $scope.add_item.media_type});
		$scope.show_add = false;
		$scope.add_item = { valid:false };
		$scope.itemURL = "";
	};
	$scope.remove_item = function(item_id){
		for (var i = 0; i < $scope.playlist.length; i++) {
			if($scope.playlist[i]._id === item_id){
				$scope.playlist.splice(i, 1);
				break;
			}
		};
		$scope.removed = true;
		for(var i = 0; i < $scope.playlist.length; i++){
			$scope.playlist[i].position = i + 1;
		}
		socket.emit('playlist.remove_item', { _id: item_id });
	}
	$scope.gdataCallback = function(data){
		if(data.entry) {
			$scope.add_item.url = data.entry.media$group.yt$videoid.$t;
			$scope.add_item.duration = data.entry.media$group.media$content[0].duration;
			$scope.add_item.caption = data.entry.title.$t;
			$scope.add_item.media_type = "youtube";
			$scope.add_item.valid = true;
		} else
			$scope.add_item.valid = false;
		$scope.$apply();
	};

	$scope.$watch("playlist", function(value){
		if($scope.reordered || $scope.removed){
			var r = value.map(function(e){ return { _id: e._id, position: e.position }; });
			socket.emit('playlist.reorder', r);
		}
	}, true);
}

app.directive('dndList', function(){
	return function(scope, element, attrs){
		var toUpdate;
		var startIndex = -1;

		scope.$watch(attrs.dndList, function(value){
			toUpdate = value;
		},true);

		$(element[0]).sortable({
			items:'tr',
			start: function(event, ui){
				startIndex = ($(ui.item).index());
				scope.reordered = true;
			},
			stop: function(event, ui){
				if(socket.is_admin) {
					console.log("Item: " + toUpdate[startIndex]._id + "; Old Position: " + toUpdate[startIndex].position + "; New Position: " + ($(ui.item).index() + 1));
					var newIndex = ($(ui.item).index());
					var toMove = toUpdate[startIndex];
					toUpdate.splice(startIndex, 1);
					toUpdate.splice(newIndex,0,toMove);
					for(var i = 0; i < scope.playlist.length; i++){
						scope.playlist[i].position = i + 1;
					}
				}
				scope.$apply(scope.playlist);
			},
			axis: 'y'
		});
	};
});
function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}
<|endoftext|>


<commit_before>/*
 * Juliana by Cas Ebbers <cjaebbers@gmail.com>
 * Front-end application for bar personnel, in Abscint Bars
 * supporting Alexia
 */

// src:http://phpjs.org/functions/date/
_pad = function (n, c) {
    n = n.toString();
    return n.length < c ? _pad('0' + n, c, '0') : n;
};

/*
 * LOG - logger status
 */
Log = {
    log: function (text) {
        var d = new Date();
        var h = d.getHours();
        var m = d.getMinutes();
        if (h < 10) h = '0' + h;
        if (m < 10) m = '0' + m;
        $('#log-table').append('
[' + h + ':' + m + ']	' + text + '
');
    }
};

State = {
    SALES: 0,
    PAYING: 1,
    ERROR: 2,
    CHECK: 3,
    MESSAGE: 4,

    current: this.SALES,
    toggleTo: function (newState, argument) {
        switch (newState) {
            case this.SALES:
                console.log('Changing to SALES...');
                this.current = this.SALES;

                clearInterval(Receipt.counterInterval);
                Receipt.clear();
                $('#payment-receipt').html('');
                $('#countdownbox').show();

                this._hideAllScreens();
                $('#cashier-screen').show();
                break;
            case this.CHECK:
                console.log('Changing to CHECK...');
                this.current = this.CHECK;
                break;
            case this.PAYING:
                console.log('Changing to PAYING...');
                this.current = this.PAYING;
                this._hideAllScreens();

                var receipt = Receipt.getReceipt();
                var receiptHTML = '';
                var total = 0;
                for (var i = 0; i < receipt.length; i++) {
                    receiptHTML += '
';
                    receiptHTML += '' + Settings.products[receipt[i].product].name + '	';
                    receiptHTML += '' + receipt[i].amount + '	';
                    receiptHTML += '€' + (receipt[i].price / 100).toFixed(2) + '	';
                    receiptHTML += '
';
                    total += receipt[i].price;
                }
                receiptHTML += '
Totaal:		€' + (total / 100).toFixed(2) + '
';
                $('#payment-receipt').html(receiptHTML);

                $('#rfid-screen').show();
                break;
            case this.ERROR:
                this.current = this.ERROR;
                this._hideAllScreens();

                $('#current-error').html(argument);

                $('#error-screen').show();
                break;
            case this.MESSAGE:
                console.log('Changing to MESSAGE...');
                this.current = this.MESSAGE;
                this._hideAllScreens();

                $('#current-message').html(argument);
                $('#message-screen').show();
                break;
            default:
                console.log('Error: no known state');
                break;
        }
        $('.btn').attr('draggable', false).on('dragstart', function () {
            return false;
        });
    },

    _hideAllScreens: function () {
        $('#rfid-screen').hide();
        $('#cashier-screen').hide();
        $('#error-screen').hide();
        $('#message-screen').hide();
    }
};

/*
 * NFC SCAN
 */
Scanner = {
    init: function () {
        var scanner = this;
        var socket;

        if (Settings.androidapp) {
            // Juliana app on Android will not connect if a protocol is specified
            socket = new WebSocket('ws://localhost:3000');
        } else {
            // JulianaNFC_C application on Windows will not connect without nfc protocol
            socket = new WebSocket('ws://localhost:3000', 'nfc');
        }

        socket.onmessage = function (event) {
            var rfid = JSON.parse(event.data);
            scanner.action(rfid);
        };

    },
    action: function (rfid) {
        console.log('CurrentState: ' + State.current);
        if (State.current === State.SALES) {
            if (Receipt.getReceipt().length > 0) {
                Receipt.pay(rfid);
            } else {
                console.log('Info: receipt empty');
                Display.set('Please select products!');
            }
        } else if (State.current === State.CHECK) {
            console.log('Requesting check');
            User.check(rfid);
        } else {
            console.log('Error: not on SALES or CHECK screen');
        }
    }
};

/*
 * DISPLAY - upper status line
 */
Display = {
    set: function (text) {
        $('#display').html(text);
    },
    flash: function () {
        $('#display').effect('shake').effect('highlight', {color: '#fcc'});
    }
};

/*
 * RECEIPT - left panel
 */
Receipt = {
    index: 0,
    receipt: [],
    counterInterval: null,
    payData: null,
    add: function (product, quantity) {
        if (State.current !== State.SALES) {
            console.log('Error: not on SALES screen');
            Display.flash();
            return;
        }

        //add product to receipt (visually)
        var desc = $('.tab-sale a[data-product="' + product + '"]').text();
        if (quantity !== 1) desc += ' × ' + quantity;

        var price = ((quantity * Settings.products[product].price) / 100).toFixed(2);

        $('#receipt-table').append('
X' + desc + '	€' + price + '
');

        //add product to actual receipt
        this.receipt[this.index] = {
            'product': product,
            'amount': quantity,
            'price': quantity * Settings.products[product].price
        };
        this.index++;

        this.updateTotalAmount();

        Display.set('OK');
    },
    remove: function (index) {
        //remove product from receipt (visually)
        $('#receipt-table').find('tr[data-pid="' + index + '"]').remove();

        //remove product from actual receipt
        this.receipt[index] = undefined;
        this.updateTotalAmount();
    },
    updateTotalAmount: function () {
        // generate total
        var sum = 0;
        for (var i = 0; i < this.receipt.length; i++) {
            if (this.receipt[i]) {
                sum += this.receipt[i].amount * Settings.products[this.receipt[i].product].price;
            }
        }
        var amount = (sum / 100).toFixed(2);
        $('#receipt-total').find('input').val('' + amount);
        return sum;
    },
    addText: function (text, quantity) {
        $('#receipt-table').append('
' + text + '	' + quantity + '
');
        Display.set('OK');
    },
    clear: function () {
        $('#receipt-table').empty();
        this.receipt = [];
        this.index = 0;
        this.updateTotalAmount();
    },
    getReceipt: function () {
        //Filter empty entries from the receipt
        var receipt = this.receipt.filter(Boolean);

        var cleanReceipt = [];
        var foundProducts = [];
        for (var i = 0; i < receipt.length; i++) {
            if ($.inArray(receipt[i].product, foundProducts) !== -1) {
                //add to existing product in receipt
                for (var j = 0; j < cleanReceipt.length; j++) {
                    if (cleanReceipt[j].product === receipt[i].product) {
                        cleanReceipt[j].amount += receipt[i].amount;
                        cleanReceipt[j].price += receipt[i].price;
                    }
                }
            } else {
                //First time this product get's added
                //add product to foundProducts and cleanReceipt
                foundProducts.push(receipt[i].product);
                cleanReceipt.push($.extend({}, receipt[i]));
            }
        }
        return cleanReceipt;
    },
    pay: function (rfid) {
        State.toggleTo(State.PAYING);

        console.log('Card scanned. Retrieving userData for: ' + rfid);
        User.retrieveData(rfid, function (result) {
            Receipt.continuePay(result, rfid);
        });

    },
    continuePay: function (userData, rfid) {
        console.log('continuePay was called: ');
        console.log(userData);
        if (!userData) {
            State.toggleTo(State.ERROR, 'RFID card retrieval failed');
        } else if (userData.error) {
            State.toggleTo(State.ERROR, 'Error authenticating: ' + userData.error.message);
        } else {
            console.log('Userdata received correctly. Proceeding to countdown.');

            Receipt.payData = {
                event_id: Settings.event_id,
                user_id: userData.result.user.id,
                purchases: Receipt.getReceipt(),
                rfid_data: rfid
            };

            var countdown = Settings.countdown - 1;
            $('#payment-countdown').text(countdown + 1);
            Receipt.counterInterval = setInterval(function () {
                $('#payment-countdown').text(countdown);
                if (countdown === 0) {
                    Receipt.payNow();
                }
                countdown--;
            }, 1000);
        }
    },
    payNow: function () {
        console.log('Processing payment now.');
        var rpcRequest = {
            jsonrpc: '2.0',
            method: 'juliana.order.save',
            params: Receipt.payData,
            id: 1
        };

        clearInterval(Receipt.counterInterval);
        Receipt.confirmPay(rpcRequest);

    },
    confirmPay: function (rpcRequest) {
        IAjax.request(rpcRequest, function (result) {
            if (result.error) {
                State.toggleTo(State.ERROR, 'Error with payment: ' + result.error);
            } else {
                State.toggleTo(State.SALES);
            }
        });
    },
    cash: function () {
        console.log('Paying cash');
        var sum = Receipt.updateTotalAmount();
        var amount = Math.ceil(sum / 10) * 10;
        State.toggleTo(State.MESSAGE, 'Dat wordt dan € ' + (amount/100).toFixed(2));
    }
};

/*
 * INPUT - processes
 */
Input = {
    prompt: '',
    latch_command: '',
    stroke: function (input) {
        // must be a string
        if (typeof input !== 'string') return;
        // don't allow prepended zeroes
        if (input === '0' && this.prompt === '') return;
        // add to prompt
        this.prompt += input;
        Display.set(this.prompt);
    },
    read: function () {
        // parse the input as integer and pass it on
        return parseInt(this.prompt);
    },
    isEmpty: function () {
        return this.prompt == '';
    },
    reset: function () {
        if (this.latch_command !== '') {
            eval(this.latch_command);
            this.latch_command = '';
        }

        this.prompt = '';
    },
    latch: function (command) {
        this.latch_command = command;
    }
};

/*
 * SALES - individual sales, beverages not paid with a "borrelkaart"
 */
Sales = {
    add: function (product, quantity) {
        // add item to receipt
        quantity = !quantity ? 1 : quantity;

        Receipt.add(product, quantity);
    }
};

User = {
    retrieveData: function (rfid, callback) {
        console.log('RetrieveData called!');
        var data = {
            event_id: Settings.event_id,
            rfid: rfid
        };
        var rpcRequest = {
            jsonrpc: '2.0',
            method: 'juliana.rfid.get',
            params: data,
            id: 1
        };
        console.log('Sending request: ' + JSON.stringify(rpcRequest));
        IAjax.request(rpcRequest, callback);
    },
    check: function (rfid) {
        console.log('Card scanned. Retrieving userData for: ' + rfid);
        User.retrieveData(rfid, function (data) {
            Display.set('?');
            User.continueCheck(data.result.user);
        });
    },
    continueCheck: function (user) {
        console.log(JSON.stringify(user));
        var rpcRequest = {
            jsonrpc: '2.0',
            method: 'juliana.user.check',
            params: {event_id: Settings.event_id, user_id: user.id},
            id: 1
        };
        IAjax.request(rpcRequest, function (data) {
            State.toggleTo(State.MESSAGE, user.first_name + " heeft op deze borrel al €" + (data.result / 100).toFixed(2) + " verbruikt.");
        });
    }
};

IAjax = {
    request: function (data, callback) {
        console.log('IAjax sent: ' + JSON.stringify(data));
        var settings = {
            data: JSON.stringify(data),
            url: Settings.api_url,
            dataType: "json",
            type: "POST",
            success: function (result) {
                console.log('Succesfully sent: ' + result);
                if (callback) {
                    console.log('Response received: calling callback.');
                    callback(result);
                }
            },
            error: function (error) {
                var result = JSON.parse(error.responseText);
                console.log('IAjax request failed');
                State.toggleTo(State.ERROR, result.error.message);
            }
        };
        jQuery.ajax(settings);
    }
};

$(function () {
    Scanner.init();

    State.toggleTo(State.SALES);

    $('.btn-keypad').click(function () {
        Input.stroke($(this).html());
    });

    $(document).keydown(function (event) {
        console.log(event.which);
        if(event.which >= 48 && event.which <= 57) // 48 is the keycode for 0, 57 for 9
            Input.stroke((event.which - 48).toString());
    });

    $('.command').click(function () {
        var reset = true;

        switch ($(this).data('command')) {
            case 'clear':
                Display.set('?');
                break;
            case 'sales':
                Sales.add($(this).data('product'), Input.read());
                break;
            case 'cancel':
                Display.set('?');
                State.toggleTo(State.SALES);
                Receipt.clear();
                break;
            case 'check':
                State.toggleTo(State.CHECK);
                Display.set('Scan een kaart');
                break;
            case 'cash':
                Receipt.cash();
                break;
            case 'cancelPayment':
                State.toggleTo(State.SALES);
                break;
            case 'payNow':
                Receipt.payNow();
                break;
            case 'ok':
                State.toggleTo(State.SALES);
                break;
            default:
                Display.set('ongeimplementeerde functie');
                Display.flash();
                break;
        }

        if (reset) Input.reset();
    });
});
<commit_msg>Remove console.log for text input<commit_after>/*
 * Juliana by Cas Ebbers <cjaebbers@gmail.com>
 * Front-end application for bar personnel, in Abscint Bars
 * supporting Alexia
 */

// src:http://phpjs.org/functions/date/
_pad = function (n, c) {
    n = n.toString();
    return n.length < c ? _pad('0' + n, c, '0') : n;
};

/*
 * LOG - logger status
 */
Log = {
    log: function (text) {
        var d = new Date();
        var h = d.getHours();
        var m = d.getMinutes();
        if (h < 10) h = '0' + h;
        if (m < 10) m = '0' + m;
        $('#log-table').append('
[' + h + ':' + m + ']	' + text + '
');
    }
};

State = {
    SALES: 0,
    PAYING: 1,
    ERROR: 2,
    CHECK: 3,
    MESSAGE: 4,

    current: this.SALES,
    toggleTo: function (newState, argument) {
        switch (newState) {
            case this.SALES:
                console.log('Changing to SALES...');
                this.current = this.SALES;

                clearInterval(Receipt.counterInterval);
                Receipt.clear();
                $('#payment-receipt').html('');
                $('#countdownbox').show();

                this._hideAllScreens();
                $('#cashier-screen').show();
                break;
            case this.CHECK:
                console.log('Changing to CHECK...');
                this.current = this.CHECK;
                break;
            case this.PAYING:
                console.log('Changing to PAYING...');
                this.current = this.PAYING;
                this._hideAllScreens();

                var receipt = Receipt.getReceipt();
                var receiptHTML = '';
                var total = 0;
                for (var i = 0; i < receipt.length; i++) {
                    receiptHTML += '
';
                    receiptHTML += '' + Settings.products[receipt[i].product].name + '	';
                    receiptHTML += '' + receipt[i].amount + '	';
                    receiptHTML += '€' + (receipt[i].price / 100).toFixed(2) + '	';
                    receiptHTML += '
';
                    total += receipt[i].price;
                }
                receiptHTML += '
Totaal:		€' + (total / 100).toFixed(2) + '
';
                $('#payment-receipt').html(receiptHTML);

                $('#rfid-screen').show();
                break;
            case this.ERROR:
                this.current = this.ERROR;
                this._hideAllScreens();

                $('#current-error').html(argument);

                $('#error-screen').show();
                break;
            case this.MESSAGE:
                console.log('Changing to MESSAGE...');
                this.current = this.MESSAGE;
                this._hideAllScreens();

                $('#current-message').html(argument);
                $('#message-screen').show();
                break;
            default:
                console.log('Error: no known state');
                break;
        }
        $('.btn').attr('draggable', false).on('dragstart', function () {
            return false;
        });
    },

    _hideAllScreens: function () {
        $('#rfid-screen').hide();
        $('#cashier-screen').hide();
        $('#error-screen').hide();
        $('#message-screen').hide();
    }
};

/*
 * NFC SCAN
 */
Scanner = {
    init: function () {
        var scanner = this;
        var socket;

        if (Settings.androidapp) {
            // Juliana app on Android will not connect if a protocol is specified
            socket = new WebSocket('ws://localhost:3000');
        } else {
            // JulianaNFC_C application on Windows will not connect without nfc protocol
            socket = new WebSocket('ws://localhost:3000', 'nfc');
        }

        socket.onmessage = function (event) {
            var rfid = JSON.parse(event.data);
            scanner.action(rfid);
        };

    },
    action: function (rfid) {
        console.log('CurrentState: ' + State.current);
        if (State.current === State.SALES) {
            if (Receipt.getReceipt().length > 0) {
                Receipt.pay(rfid);
            } else {
                console.log('Info: receipt empty');
                Display.set('Please select products!');
            }
        } else if (State.current === State.CHECK) {
            console.log('Requesting check');
            User.check(rfid);
        } else {
            console.log('Error: not on SALES or CHECK screen');
        }
    }
};

/*
 * DISPLAY - upper status line
 */
Display = {
    set: function (text) {
        $('#display').html(text);
    },
    flash: function () {
        $('#display').effect('shake').effect('highlight', {color: '#fcc'});
    }
};

/*
 * RECEIPT - left panel
 */
Receipt = {
    index: 0,
    receipt: [],
    counterInterval: null,
    payData: null,
    add: function (product, quantity) {
        if (State.current !== State.SALES) {
            console.log('Error: not on SALES screen');
            Display.flash();
            return;
        }

        //add product to receipt (visually)
        var desc = $('.tab-sale a[data-product="' + product + '"]').text();
        if (quantity !== 1) desc += ' × ' + quantity;

        var price = ((quantity * Settings.products[product].price) / 100).toFixed(2);

        $('#receipt-table').append('
X' + desc + '	€' + price + '
');

        //add product to actual receipt
        this.receipt[this.index] = {
            'product': product,
            'amount': quantity,
            'price': quantity * Settings.products[product].price
        };
        this.index++;

        this.updateTotalAmount();

        Display.set('OK');
    },
    remove: function (index) {
        //remove product from receipt (visually)
        $('#receipt-table').find('tr[data-pid="' + index + '"]').remove();

        //remove product from actual receipt
        this.receipt[index] = undefined;
        this.updateTotalAmount();
    },
    updateTotalAmount: function () {
        // generate total
        var sum = 0;
        for (var i = 0; i < this.receipt.length; i++) {
            if (this.receipt[i]) {
                sum += this.receipt[i].amount * Settings.products[this.receipt[i].product].price;
            }
        }
        var amount = (sum / 100).toFixed(2);
        $('#receipt-total').find('input').val('' + amount);
        return sum;
    },
    addText: function (text, quantity) {
        $('#receipt-table').append('
' + text + '	' + quantity + '
');
        Display.set('OK');
    },
    clear: function () {
        $('#receipt-table').empty();
        this.receipt = [];
        this.index = 0;
        this.updateTotalAmount();
    },
    getReceipt: function () {
        //Filter empty entries from the receipt
        var receipt = this.receipt.filter(Boolean);

        var cleanReceipt = [];
        var foundProducts = [];
        for (var i = 0; i < receipt.length; i++) {
            if ($.inArray(receipt[i].product, foundProducts) !== -1) {
                //add to existing product in receipt
                for (var j = 0; j < cleanReceipt.length; j++) {
                    if (cleanReceipt[j].product === receipt[i].product) {
                        cleanReceipt[j].amount += receipt[i].amount;
                        cleanReceipt[j].price += receipt[i].price;
                    }
                }
            } else {
                //First time this product get's added
                //add product to foundProducts and cleanReceipt
                foundProducts.push(receipt[i].product);
                cleanReceipt.push($.extend({}, receipt[i]));
            }
        }
        return cleanReceipt;
    },
    pay: function (rfid) {
        State.toggleTo(State.PAYING);

        console.log('Card scanned. Retrieving userData for: ' + rfid);
        User.retrieveData(rfid, function (result) {
            Receipt.continuePay(result, rfid);
        });

    },
    continuePay: function (userData, rfid) {
        console.log('continuePay was called: ');
        console.log(userData);
        if (!userData) {
            State.toggleTo(State.ERROR, 'RFID card retrieval failed');
        } else if (userData.error) {
            State.toggleTo(State.ERROR, 'Error authenticating: ' + userData.error.message);
        } else {
            console.log('Userdata received correctly. Proceeding to countdown.');

            Receipt.payData = {
                event_id: Settings.event_id,
                user_id: userData.result.user.id,
                purchases: Receipt.getReceipt(),
                rfid_data: rfid
            };

            var countdown = Settings.countdown - 1;
            $('#payment-countdown').text(countdown + 1);
            Receipt.counterInterval = setInterval(function () {
                $('#payment-countdown').text(countdown);
                if (countdown === 0) {
                    Receipt.payNow();
                }
                countdown--;
            }, 1000);
        }
    },
    payNow: function () {
        console.log('Processing payment now.');
        var rpcRequest = {
            jsonrpc: '2.0',
            method: 'juliana.order.save',
            params: Receipt.payData,
            id: 1
        };

        clearInterval(Receipt.counterInterval);
        Receipt.confirmPay(rpcRequest);

    },
    confirmPay: function (rpcRequest) {
        IAjax.request(rpcRequest, function (result) {
            if (result.error) {
                State.toggleTo(State.ERROR, 'Error with payment: ' + result.error);
            } else {
                State.toggleTo(State.SALES);
            }
        });
    },
    cash: function () {
        console.log('Paying cash');
        var sum = Receipt.updateTotalAmount();
        var amount = Math.ceil(sum / 10) * 10;
        State.toggleTo(State.MESSAGE, 'Dat wordt dan € ' + (amount/100).toFixed(2));
    }
};

/*
 * INPUT - processes
 */
Input = {
    prompt: '',
    latch_command: '',
    stroke: function (input) {
        // must be a string
        if (typeof input !== 'string') return;
        // don't allow prepended zeroes
        if (input === '0' && this.prompt === '') return;
        // add to prompt
        this.prompt += input;
        Display.set(this.prompt);
    },
    read: function () {
        // parse the input as integer and pass it on
        return parseInt(this.prompt);
    },
    isEmpty: function () {
        return this.prompt == '';
    },
    reset: function () {
        if (this.latch_command !== '') {
            eval(this.latch_command);
            this.latch_command = '';
        }

        this.prompt = '';
    },
    latch: function (command) {
        this.latch_command = command;
    }
};

/*
 * SALES - individual sales, beverages not paid with a "borrelkaart"
 */
Sales = {
    add: function (product, quantity) {
        // add item to receipt
        quantity = !quantity ? 1 : quantity;

        Receipt.add(product, quantity);
    }
};

User = {
    retrieveData: function (rfid, callback) {
        console.log('RetrieveData called!');
        var data = {
            event_id: Settings.event_id,
            rfid: rfid
        };
        var rpcRequest = {
            jsonrpc: '2.0',
            method: 'juliana.rfid.get',
            params: data,
            id: 1
        };
        console.log('Sending request: ' + JSON.stringify(rpcRequest));
        IAjax.request(rpcRequest, callback);
    },
    check: function (rfid) {
        console.log('Card scanned. Retrieving userData for: ' + rfid);
        User.retrieveData(rfid, function (data) {
            Display.set('?');
            User.continueCheck(data.result.user);
        });
    },
    continueCheck: function (user) {
        console.log(JSON.stringify(user));
        var rpcRequest = {
            jsonrpc: '2.0',
            method: 'juliana.user.check',
            params: {event_id: Settings.event_id, user_id: user.id},
            id: 1
        };
        IAjax.request(rpcRequest, function (data) {
            State.toggleTo(State.MESSAGE, user.first_name + " heeft op deze borrel al €" + (data.result / 100).toFixed(2) + " verbruikt.");
        });
    }
};

IAjax = {
    request: function (data, callback) {
        console.log('IAjax sent: ' + JSON.stringify(data));
        var settings = {
            data: JSON.stringify(data),
            url: Settings.api_url,
            dataType: "json",
            type: "POST",
            success: function (result) {
                console.log('Succesfully sent: ' + result);
                if (callback) {
                    console.log('Response received: calling callback.');
                    callback(result);
                }
            },
            error: function (error) {
                var result = JSON.parse(error.responseText);
                console.log('IAjax request failed');
                State.toggleTo(State.ERROR, result.error.message);
            }
        };
        jQuery.ajax(settings);
    }
};

$(function () {
    Scanner.init();

    State.toggleTo(State.SALES);

    $('.btn-keypad').click(function () {
        Input.stroke($(this).html());
    });

    $(document).keydown(function (event) {
        if(event.which >= 48 && event.which <= 57) // 48 is the keycode for 0, 57 for 9
            Input.stroke((event.which - 48).toString());
    });

    $('.command').click(function () {
        var reset = true;

        switch ($(this).data('command')) {
            case 'clear':
                Display.set('?');
                break;
            case 'sales':
                Sales.add($(this).data('product'), Input.read());
                break;
            case 'cancel':
                Display.set('?');
                State.toggleTo(State.SALES);
                Receipt.clear();
                break;
            case 'check':
                State.toggleTo(State.CHECK);
                Display.set('Scan een kaart');
                break;
            case 'cash':
                Receipt.cash();
                break;
            case 'cancelPayment':
                State.toggleTo(State.SALES);
                break;
            case 'payNow':
                Receipt.payNow();
                break;
            case 'ok':
                State.toggleTo(State.SALES);
                break;
            default:
                Display.set('ongeimplementeerde functie');
                Display.flash();
                break;
        }

        if (reset) Input.reset();
    });
});
<|endoftext|>


<commit_before><commit_msg>changes to slider now affectes volume<commit_after><|endoftext|>


<commit_before>---
---
$(document).ready(function() {
  'use strict';
  // BROWSER CHECKS
  // =======================================================
  // TODO Need to refactor initial browser checks - this is a mess!
  const isIE11 = !!window.MSInputMethodContext && !!document.documentMode; // Note: does not detect <IE11
  const isMobile = window.matchMedia('only screen and (max-width: 992px)');
  const hasAlgolia = $('#grants .card-panel-header .search');
  let isSupported = browserTest();
  let allowsCookies = cookieTest();
  let allowsLocalStorage = storageTest();

  // Load Vue if supported
  const vue = document.createElement('script');
  vue.src = '{{ site.baseurl }}/assets/js/bundle.js?v={{ site.time | date: "%Y%m%d"}}';
  if (!isIE11 && !isMobile.matches && allowsCookies && allowsLocalStorage && isSupported) {
    document.body.appendChild(vue);
  } else {
    $('.js-vue-check').addClass( 'hidden' ); // Hide UI elements created in DOM, but handled by Vue
  }

  // Show message if not supported
  if (isIE11 || !isSupported) {
    const toastContent = 'Your browser is currently not supported.
Many useful features may not work.<button href="https://outdatedbrowser.com/en" class="btn-flat yellow-text toast-action-browser-suggestion">Browser Suggestions</button>';
    M.Toast.dismissAll();
    M.toast({
      'html': toastContent,
      'displayLength': 10000,
    });
    $('.toast-action-browser-suggestion').on('click', function() {
      const target = $(this).attr('href');
      window.location.href = target;
    });
    // Hide Algolia elements
    $('.js-ie-check').addClass( 'hidden' );
  }

  function browserTest() {
    const parent = document.createElement('div');
    const el = document.createElement('span');
    try {
      parent.prepend(el); // Using ParentNode.prepend() as proxy for supported browsers
      return true;
    } catch (e) {
      return false;
    }
  }

  function cookieTest() {
    let cookieEnabled = navigator.cookieEnabled;
    if (!cookieEnabled) {
      document.cookie = 'testcookie';
      cookieEnabled = document.cookie.indexOf('testcookie') !== -1;
      document.cookie = 'testcookie; expires=Thu, 01-Jan-1970 00:00:01 GMT';
    }
    return cookieEnabled || showCookieFail();
  }

  function showCookieFail() {
    if (!isIE11 && isSupported) {
      M.toast({
        'html': 'Enable cookies to view available profile updates',
      });
    }
    return false;
  }

  function storageTest() {
    const test = 'test';
    try {
      localStorage.setItem(test, test);
      localStorage.removeItem(test);
      return true;
    } catch (e) {
      return false;
    }
  }

  // NAVBAR
  // =======================================================
  const header = $('.header');
  const navbar = $('.navbar-profile');
  const range = 64; // Height of navbar

  $(window).on('scroll', function() {
    let scrollTop = $(this).scrollTop();
    let height = header.outerHeight();
    let offset = height / 2;
    let calc = 1 - (scrollTop - offset + range) / range;

    header.css({ 'opacity': calc });

    if (calc > '1') {
      header.css({ 'opacity': 1 });
      navbar.addClass('affix-top');
      navbar.removeClass('affix');
    } else if ( calc < '0' ) {
      header.css({ 'opacity': 0 });
      navbar.addClass('affix');
      navbar.removeClass('affix-top');
    }
  });

  // INIT MATERIALIZE COMPONENTS
  // =======================================================
  window.onload = function() {
    const elemsNavMore = document.getElementById('primary-navbar-dropdown-trigger');
    const optionsNavMore = {
      'container': 'main-nav',
      'constrainWidth': false,
    };
    M.Dropdown.init(elemsNavMore, optionsNavMore);
    $('.sidenav').sidenav();
    $('#community-sidebar').sidenav({ 'edge': 'right'});
    $('.tooltipped:not(.v-tooltipped)').tooltip(); // :not ensures Vue handles relevant initiation for Vue-controlled elements
    $('.collapsible').collapsible({
      'accordion': false,
    });

    $('.collapsible-grants-table').collapsible({
      'accordion': false,
      // TODO Use onOpenStart to add spinning icon
      // onOpenStart: function(el) {
      //   $(el).find('.collapsible-header i').addClass('md-spin');
      // }
      'onOpenEnd': function(el) {
        $(el).find('.collapsible-header i').removeClass('md-spin');
      },
    });

    // TODO Use onOpenStart to add spinning icon
    // Unsure of root cause - possible Materialize bug?
    $('.collapsible-grants-table .collapsible-header').click(function(e) {
      if (!$(this).parent().hasClass('active')) {
        e.stopPropagation();
        $(this).find('i').addClass('md-spin');
        $(this).find('i').removeClass('bounce');
        setTimeout(function() {
          $('.collapsible-grants-table').collapsible('open');
        }, 100);
      }
    });
  };

  // FIXED HEADERS
  // =======================================================
  // Grants header is fixed only on non-mobile devices with Algolia enabled
  // See also search.js - Need to re-init grants header after search results populate to capture proper div height

  function enableGrantsFixedHeader() {
    const grantsHeader = $('#grants .card-panel-header');
    grantsHeader.addClass('pushpin-nav pushpin-nav-search');
    grantsHeader.attr('data-target', 'grants');
  }

  if (!isMobile.matches && hasAlgolia.length && !isIE11) {
    enableGrantsFixedHeader();
  }

  if ($('.pushpin-nav').length) {
    $('.pushpin-nav').each(function() {
      let $this = $(this);
      let $id = $(this).attr('data-target');
      let $target = $('#' + $(this).attr('data-target'));
      let targetBottom = $target.offset().top + $target.height();
      let targetOffset = 0;
      if ($id === 'main-nav') {
        targetBottom = Infinity;
      } else {
        targetOffset = range;
      }
      $this.pushpin({
        'top': $target.offset().top,
        'bottom': targetBottom,
        'offset': targetOffset,
      });
    });
  }

  // SMOOTH SCROLL
  // =======================================================
  $('.scrolly').click(function() {
    const target = $(this).attr('href');
    const newPosition = $(target).offset().top - 64;
    $('html, body').stop().animate({ 'scrollTop': newPosition }, 500);
  });

  $('.nav-primary li a.scrolly').on('click', function() {
    // collapse mobile header
    if (isMobile.matches) {
      $('.sidenav').sidenav('close');
    }
  });

  // FILINGS
  // =======================================================
  // Add filing links
  $('.js-filings-pdf').each(function() {
    addFilingURL($(this));
  });

  function addFilingURL(el) {
    const ein = el.data('ein');
    const einShort = ein.toString().substring(0, 3);
    const taxPeriod = el.data('tax-period');
    // Foundation Center: http://990s.foundationcenter.org/990pf_pdf_archive/272/272624875/272624875_201412_990PF.pdf
    const urlPDF = 'http://990s.foundationcenter.org/990pf_pdf_archive/' +
                 einShort + '/' +
                 ein + '/' +
                 ein + '_' +
                 taxPeriod + '_990PF.pdf';
    el.attr('data-url-pdf', urlPDF);
    el.attr('href', urlPDF);
  }

  // Check if filing is available
  const gcf = 'https://us-central1-infinite-badge-163220.cloudfunctions.net/checkUrl';

  $('.js-filings-pdf').click(function(e) {
    e.preventDefault();
    M.toast({
      'html': 'Redirecting to latest 990...',
    });
    const elem = $(this);
    const target = $(this).attr('href');
    $.ajax({
      'method': 'POST',
      'url': gcf,
      'data': { 'target': target },
    })
      .done(function( res ) {
        if (res) {
          window.location.href = target;
        } else {
          elem.addClass('disabled');
          M.Toast.dismissAll();
          M.toast({
            'html': 'PDF not yet available. Try a prior year.',
          });
        }
      })
      .fail(function(xhr, textStatus, error) { // eslint-disable-line no-unused-vars
        const toastContent = 'Something went wrong.<button href="http://foundationcenter.org/find-funding/990-finder" class="btn-flat toast-action">Try Here.</button>';
        M.Toast.dismissAll();
        M.toast({
          'html': toastContent,
          'displayLength': 10000,
        });
      });
  });
});
<commit_msg>Set header opacity on page load [fixes #80]<commit_after>---
---
$(document).ready(function() {
  'use strict';
  // BROWSER CHECKS
  // =======================================================
  // TODO Need to refactor initial browser checks - this is a mess!
  const isIE11 = !!window.MSInputMethodContext && !!document.documentMode; // Note: does not detect <IE11
  const isMobile = window.matchMedia('only screen and (max-width: 992px)');
  const hasAlgolia = $('#grants .card-panel-header .search');
  let isSupported = browserTest();
  let allowsCookies = cookieTest();
  let allowsLocalStorage = storageTest();

  // Load Vue if supported
  const vue = document.createElement('script');
  vue.src = '{{ site.baseurl }}/assets/js/bundle.js?v={{ site.time | date: "%Y%m%d"}}';
  if (!isIE11 && !isMobile.matches && allowsCookies && allowsLocalStorage && isSupported) {
    document.body.appendChild(vue);
  } else {
    $('.js-vue-check').addClass( 'hidden' ); // Hide UI elements created in DOM, but handled by Vue
  }

  // Show message if not supported
  if (isIE11 || !isSupported) {
    const toastContent = 'Your browser is currently not supported.
Many useful features may not work.<button href="https://outdatedbrowser.com/en" class="btn-flat yellow-text toast-action-browser-suggestion">Browser Suggestions</button>';
    M.Toast.dismissAll();
    M.toast({
      'html': toastContent,
      'displayLength': 10000,
    });
    $('.toast-action-browser-suggestion').on('click', function() {
      const target = $(this).attr('href');
      window.location.href = target;
    });
    // Hide Algolia elements
    $('.js-ie-check').addClass( 'hidden' );
  }

  function browserTest() {
    const parent = document.createElement('div');
    const el = document.createElement('span');
    try {
      parent.prepend(el); // Using ParentNode.prepend() as proxy for supported browsers
      return true;
    } catch (e) {
      return false;
    }
  }

  function cookieTest() {
    let cookieEnabled = navigator.cookieEnabled;
    if (!cookieEnabled) {
      document.cookie = 'testcookie';
      cookieEnabled = document.cookie.indexOf('testcookie') !== -1;
      document.cookie = 'testcookie; expires=Thu, 01-Jan-1970 00:00:01 GMT';
    }
    return cookieEnabled || showCookieFail();
  }

  function showCookieFail() {
    if (!isIE11 && isSupported) {
      M.toast({
        'html': 'Enable cookies to view available profile updates',
      });
    }
    return false;
  }

  function storageTest() {
    const test = 'test';
    try {
      localStorage.setItem(test, test);
      localStorage.removeItem(test);
      return true;
    } catch (e) {
      return false;
    }
  }

  // NAVBAR
  // =======================================================
  const header = $('.header');
  const navbar = $('.navbar-profile');
  const range = 64; // Height of navbar

  // Set header opacity on page load
  setHeaderOpacity();

  // Adjust opacity after scrolling
  $(window).on('scroll', function() {
    setHeaderOpacity();
  });

  function setHeaderOpacity() {
    let scrollTop = $(window).scrollTop();
    let height = header.outerHeight();
    let offset = height / 2;
    let calc = 1 - (scrollTop - offset + range) / range;
    header.css({ 'opacity': calc });

    if (calc > '1') {
      header.css({ 'opacity': 1 });
      navbar.addClass('affix-top');
      navbar.removeClass('affix');
    } else if ( calc < '0' ) {
      header.css({ 'opacity': 0 });
      navbar.addClass('affix');
      navbar.removeClass('affix-top');
    }
  }

  // INIT MATERIALIZE COMPONENTS
  // =======================================================
  window.onload = function() {
    const elemsNavMore = document.getElementById('primary-navbar-dropdown-trigger');
    const optionsNavMore = {
      'container': 'main-nav',
      'constrainWidth': false,
    };
    M.Dropdown.init(elemsNavMore, optionsNavMore);
    $('.sidenav').sidenav();
    $('#community-sidebar').sidenav({ 'edge': 'right'});
    $('.tooltipped:not(.v-tooltipped)').tooltip(); // :not ensures Vue handles relevant initiation for Vue-controlled elements
    $('.collapsible').collapsible({
      'accordion': false,
    });

    $('.collapsible-grants-table').collapsible({
      'accordion': false,
      // TODO Use onOpenStart to add spinning icon
      // onOpenStart: function(el) {
      //   $(el).find('.collapsible-header i').addClass('md-spin');
      // }
      'onOpenEnd': function(el) {
        $(el).find('.collapsible-header i').removeClass('md-spin');
      },
    });

    // TODO Use onOpenStart to add spinning icon
    // Unsure of root cause - possible Materialize bug?
    $('.collapsible-grants-table .collapsible-header').click(function(e) {
      if (!$(this).parent().hasClass('active')) {
        e.stopPropagation();
        $(this).find('i').addClass('md-spin');
        $(this).find('i').removeClass('bounce');
        setTimeout(function() {
          $('.collapsible-grants-table').collapsible('open');
        }, 100);
      }
    });
  };

  // FIXED HEADERS
  // =======================================================
  // Grants header is fixed only on non-mobile devices with Algolia enabled
  // See also search.js - Need to re-init grants header after search results populate to capture proper div height

  function enableGrantsFixedHeader() {
    const grantsHeader = $('#grants .card-panel-header');
    grantsHeader.addClass('pushpin-nav pushpin-nav-search');
    grantsHeader.attr('data-target', 'grants');
  }

  if (!isMobile.matches && hasAlgolia.length && !isIE11) {
    enableGrantsFixedHeader();
  }

  if ($('.pushpin-nav').length) {
    $('.pushpin-nav').each(function() {
      let $this = $(this);
      let $id = $(this).attr('data-target');
      let $target = $('#' + $(this).attr('data-target'));
      let targetBottom = $target.offset().top + $target.height();
      let targetOffset = 0;
      if ($id === 'main-nav') {
        targetBottom = Infinity;
      } else {
        targetOffset = range;
      }
      $this.pushpin({
        'top': $target.offset().top,
        'bottom': targetBottom,
        'offset': targetOffset,
      });
    });
  }

  // SMOOTH SCROLL
  // =======================================================
  $('.scrolly').click(function() {
    const target = $(this).attr('href');
    const newPosition = $(target).offset().top - 64;
    $('html, body').stop().animate({ 'scrollTop': newPosition }, 500);
  });

  $('.nav-primary li a.scrolly').on('click', function() {
    // collapse mobile header
    if (isMobile.matches) {
      $('.sidenav').sidenav('close');
    }
  });

  // FILINGS
  // =======================================================
  // Add filing links
  $('.js-filings-pdf').each(function() {
    addFilingURL($(this));
  });

  function addFilingURL(el) {
    const ein = el.data('ein');
    const einShort = ein.toString().substring(0, 3);
    const taxPeriod = el.data('tax-period');
    // Foundation Center: http://990s.foundationcenter.org/990pf_pdf_archive/272/272624875/272624875_201412_990PF.pdf
    const urlPDF = 'http://990s.foundationcenter.org/990pf_pdf_archive/' +
                 einShort + '/' +
                 ein + '/' +
                 ein + '_' +
                 taxPeriod + '_990PF.pdf';
    el.attr('data-url-pdf', urlPDF);
    el.attr('href', urlPDF);
  }

  // Check if filing is available
  const gcf = 'https://us-central1-infinite-badge-163220.cloudfunctions.net/checkUrl';

  $('.js-filings-pdf').click(function(e) {
    e.preventDefault();
    M.toast({
      'html': 'Redirecting to latest 990...',
    });
    const elem = $(this);
    const target = $(this).attr('href');
    $.ajax({
      'method': 'POST',
      'url': gcf,
      'data': { 'target': target },
    })
      .done(function( res ) {
        if (res) {
          window.location.href = target;
        } else {
          elem.addClass('disabled');
          M.Toast.dismissAll();
          M.toast({
            'html': 'PDF not yet available. Try a prior year.',
          });
        }
      })
      .fail(function(xhr, textStatus, error) { // eslint-disable-line no-unused-vars
        const toastContent = 'Something went wrong.<button href="http://foundationcenter.org/find-funding/990-finder" class="btn-flat toast-action">Try Here.</button>';
        M.Toast.dismissAll();
        M.toast({
          'html': toastContent,
          'displayLength': 10000,
        });
      });
  });
});
<|endoftext|>