<commit_before>/*
* Global vars
*/
var NAV_HEIGHT = 75;

var $w;
var $h;
var $slides;
var $components;
var $portraits;
var $play;
var $video;
var $primaryNav;
var $navButton;
var $nav;
var $navItems;
var $secondaryNav;
var $arrows;
var currentSection = '_'
var currentSectionIndex = 0;
var anchors;
var mobileSuffix;
var player;
var is_touch = Modernizr.touch;
var active_counter = null;
var begin = moment();
var aspectWidth = 16;
var aspectHeight = 9;
var optimalWidth;
var optimalHeight;
var w;
var h;
var $jplayer = null;

var resize = function() {

    $w = $(window).width();
    $h = $(window).height();

    $slides.width($w);

    optimalWidth = ($h * aspectWidth) / aspectHeight;
    optimalHeight = ($w * aspectHeight) / aspectWidth;

    w = $w;
    h = optimalHeight;

    if (optimalWidth > $w) {
        w = optimalWidth;
        h = $h;
    }
};

var setUpFullPage = function() {
    // clear all anchors
    anchors = [];

    // get the anchors

   _.each($slides, function(section) {
        var anchor = $(section).data('anchor');
        if (anchor === undefined) {
            return false;
        }
        anchors.push(anchor);
    });

    $.fn.fullpage({
        autoScrolling: false,
        anchors: anchors,
        menu: '.nav',
        verticalCentered: false,
        fixedElements: '.primary-navigation, .nav',
        resize: false,
        css3: true,
        loopHorizontal: false,
        afterRender: onPageLoad,
        afterSlideLoad: lazyLoad,
        onSlideLeave: onSlideLeave
    });
};

// after the page loads

var onPageLoad = function() {
    setSlidesForLazyLoading(0)
    // fade in
    $('body').css('opacity', 1);
};

// after a new slide loads

var lazyLoad = function(anchorLink, index, slideAnchor, slideIndex) {
    setSlidesForLazyLoading(slideIndex);

    if (slideAnchor === 'dashboard') {
        onStartCounts();
    }

    showNavigation();
};

var setSlidesForLazyLoading = function(slideIndex) {
    /*
    * Sets up a list of slides based on your position in the deck.
    * Lazy-loads images in future slides because of reasons.
    */
    var thisSlide = $slides[slideIndex];
    var nextSlide = $slides[slideIndex + 1]

    if ($(thisSlide).data('anchor')) {
        currentSection = $(thisSlide).data('anchor');
        for (i=0; i < anchors.length; i++) {
            if (anchors[i] === currentSection) {
                currentSectionIndex = i;
            }
        }
    };

    var slides = [
        $slides[slideIndex - 2],
        $slides[slideIndex - 1],
        thisSlide,
        nextSlide,
        $slides[slideIndex + 2]
    ];

    findImages(slides);

    if (!$jplayer && $(thisSlide).hasClass('video')) {
        setupVideoPlayer();
    }
}

var findImages = function(slides) {
    /*
    * Set background images on slides.
    * Should get square images for mobile.
    */

    // Mobile suffix should be blank by default.
    mobileSuffix = '';

    //
    if ($w < 769 && is_touch) {
        mobileSuffix = '-sq';
    }

    _.each($(slides), function(slide) {

        getBackgroundImage(slide);
        var containedImage = $(slide).find('.contained-image-container, .contained-image');
        getBackgroundImage(containedImage);
    });
};

var getBackgroundImage = function(container) {
    /*
    * Sets the background image on a div for our fancy slides.
    */

    if ($(container).data('bgimage')) {

        var image_filename = $(container).data('bgimage').split('.')[0];
        var image_extension = '.' + $(container).data('bgimage').split('.')[1];
        var image_path = 'assets/img/' + image_filename + mobileSuffix + image_extension;

        if ($(container).css('background-image') === 'none') {
            $(container).css('background-image', 'url(' + image_path + ')');
        }
        if ($(container).hasClass('contained-image-container')) {
            setImages($(container));
        }

     }
};

var showNavigation = function() {
    /*
    * Nav doesn't exist by default.
    * This function loads it up.
    */

    if ($slides.first().hasClass('active')) {
        /*
        * Title card gets no arrows and no nav.
        */
        $arrows.removeClass('active');
        $arrows.css({
            'opacity': 0,
            'display': 'none'
        });
        $primaryNav.css('opacity', '0');
    } else if ($slides.last().hasClass('active')) {
        /*
        * Last card gets no arrows but does have the nav.
        */
        $arrows.removeClass('active');
        $arrows.css({
            'opacity': 0,
            'display': 'none'
        });
        $primaryNav.css('opacity', '1');
    } else {
        /*
        * All of the other cards? Arrows and navs.
        */
        if (!$arrows.hasClass('active')) {
            animateArrows();
        }
        $primaryNav.css('opacity', '1');
    }
}

var animateArrows = function() {
    /*
    * Everything looks better faded. Hair; jeans; arrows.
    */
    $arrows.addClass('active');

    if ($arrows.hasClass('active')) {
        $arrows.css('display', 'block');
        var fade = _.debounce(fadeInArrows, 1);
        fade();
    }
};

var fadeInArrows = function() {
    /*
    * Debounce makes you do crazy things.
    */
    $arrows.css('opacity', 1)
};

var setImages = function(container) {
    /*
    * Image resizer from the Wolves lightbox + sets background image on a div.
    */

    // Grab Wes's properly sized width.
    var imageWidth = w;

    // Sometimes, this is wider than the window, shich is bad.
    if (imageWidth > $w) {
        imageWidth = $w;
    }

    // Set the hight as a proportion of the image width.
    var imageHeight = ((imageWidth * aspectHeight) / aspectWidth);

    // Sometimes the lightbox width is greater than the window height.
    // Center it vertically.
    if (imageWidth > $h) {
        imageTop = (imageHeight - $h) / 2;
    }

    // Sometimes the lightbox height is greater than the window height.
    // Resize the image to fit.
    if (imageHeight > $h) {
        imageWidth = ($h * aspectWidth) / aspectHeight;
        imageHeight = $h;
    }

    // Sometimes the lightbox width is greater than the window width.
    // Resize the image to fit.
    if (imageWidth > $w) {
        imageHeight = ($w * aspectHeight) / aspectWidth;
        imageWidth = $w;
    }

    // Set the top and left offsets. Image bottom includes offset for navigation
    var imageBottom = ($h - imageHeight) / 2 + 70;
    var imageLeft = ($w - imageWidth) / 2;

    // Set styles on the map images.
    $(container).css({
        'width': imageWidth + 'px',
        'height': imageHeight + 'px',
        'bottom': imageBottom + 'px',
        'left': imageLeft + 'px',
    });

};

var onSlideLeave = function(anchorLink, index, slideIndex, direction) {
    /*
    * Called when leaving a slide.
    */
    var thisSlide = $slides[slideIndex];

    if ($jplayer && $(thisSlide).hasClass('video')) {

        $(thisSlide).removeClass('video-playing');
        stopVideo();
    }
}

var goToNextSection = function() {
    $.fn.fullpage.moveTo(0, anchors[currentSectionIndex + 1]);
}

var goToNextSlide = function() {
    $.fn.fullpage.moveSlideRight();
}

var animateNav = function() {
    $navButton.find('i').toggleClass('fa-th').toggleClass('fa-times');
    $nav.toggleClass('active');
    if ($nav.hasClass('active')) {
        $nav.css('display', 'block');
        var fade = _.debounce(fadeInNav, 1);
        fade();
    }
    else {
        $nav.css('opacity', 0);
        var fade = _.debounce(fadeOutNav, 500);
        fade();
    }
}

var fadeInNav = function() {
    /*
    * Separate function because you can't pass an argument to a debounced function.
    */
    $nav.css('opacity', 1);
};

var fadeOutNav = function() {
    /*
    * Separate function because you can't pass an argument to a debounced function.
    */
    $nav.css('display', 'none');
};

var setupVideoPlayer = function() {
    /*
    * Setup jPlayer.
    */
    var computePlayerHeight = function() {
        return ($h - ($('.jp-interface').height() + NAV_HEIGHT))
    }

    $jplayer = $('.jp-jplayer').jPlayer({
        ready: function () {
            $(this).jPlayer('setMedia', {
                poster: '../assets/img/junior/junior.jpg',
                m4v: 'http://pd.npr.org/npr-mp4/npr/nprvid/2014/03/20140328_nprvid_junior-n-600000.mp4'
                webmv: '../assets/img/junior/junior-final.webm'
            });
        },
        play: function (){
            $('.jp-current-time').removeClass('hide');
            $('.jp-duration').addClass('hide');
        },
        ended: function(){
            $('.jp-current-time').addClass('hide');
            $('.jp-duration').removeClass('hide');
        },
        size: {
            width: $w,
            height: computePlayerHeight() + 'px'
        },
        swfPath: 'js/lib',
        supplied: 'm4v, webmv',
        loop: false
    });

    $(window).resize(function() {
        $jplayer.jPlayer('option', { 'size': {
            width: $w,
            height: computePlayerHeight() + 'px'
        }});
    });
};

var startVideo = function() {
    var $parent = $(this).parents('.slide.video');

    $parent.addClass('video-playing');
    $('.jp-jplayer').jPlayer('play');
}

var stopVideo = function() {
    $('.jp-jplayer').jPlayer('stop');
}

var onUpdateCounts = function(e) {
    /*
    * Updates the count based on elapsed time and known rates.
    */
    var now = moment();
    var elapsed_seconds = (now - begin) / 1000;
    var RATES = [
        ['marijuana', 0.08844],
        ['cocaine', 0.01116],
        ['illegal-entry', 0.01065],
        ['vehicles', 2.15096],
        ['pedestrians', 1.30102]
    ]

    _.each(RATES, function(count, i){
        var count_category = count[0];
        var count_number = count[1];
        var count_unit = count[2];

        $('#' + count_category + ' span.number').html(Math.round(count_number * elapsed_seconds));
    });

};

var onStartCounts = function(e) {
    /*
    * Starts the counting machinery.
    */
    active_counter = setInterval(onUpdateCounts,500);
}

var onResize = function(e) {
    if ($('.slide.active').hasClass('image-split')) {
        setImages($('.slide.active').find('.contained-image-container')[0]);
    }
}

$(document).ready(function() {
    $slides = $('.slide');
    $play_video = $('.btn-video');
    $video = $('.video');
    $components = $('.component');
    $portraits = $('.section[data-anchor="people"] .slide')
    $navButton = $('.primary-navigation-btn');
    $primaryNav = $('.primary-navigation');
    $nav = $('.nav');
    $navItems = $('.nav .section-tease');
    $secondaryNav = $('.secondary-nav-btn');
    $titleCardButton = $('.btn-play');
    $arrows = $('.controlArrow');

    setUpFullPage();
    resize();

    $play_video.on('click', startVideo);
    $navButton.on('click', animateNav);
    $navItems.on('click', animateNav);
    $secondaryNav.on('click', animateNav);
    $titleCardButton.on('click', goToNextSlide);

    // Redraw slides if the window resizes
    $(window).resize(resize);
    $(window).resize(onResize);
});
<commit_msg>COMMA JEREMY<commit_after>/*
* Global vars
*/
var NAV_HEIGHT = 75;

var $w;
var $h;
var $slides;
var $components;
var $portraits;
var $play;
var $video;
var $primaryNav;
var $navButton;
var $nav;
var $navItems;
var $secondaryNav;
var $arrows;
var currentSection = '_'
var currentSectionIndex = 0;
var anchors;
var mobileSuffix;
var player;
var is_touch = Modernizr.touch;
var active_counter = null;
var begin = moment();
var aspectWidth = 16;
var aspectHeight = 9;
var optimalWidth;
var optimalHeight;
var w;
var h;
var $jplayer = null;

var resize = function() {

    $w = $(window).width();
    $h = $(window).height();

    $slides.width($w);

    optimalWidth = ($h * aspectWidth) / aspectHeight;
    optimalHeight = ($w * aspectHeight) / aspectWidth;

    w = $w;
    h = optimalHeight;

    if (optimalWidth > $w) {
        w = optimalWidth;
        h = $h;
    }
};

var setUpFullPage = function() {
    // clear all anchors
    anchors = [];

    // get the anchors

   _.each($slides, function(section) {
        var anchor = $(section).data('anchor');
        if (anchor === undefined) {
            return false;
        }
        anchors.push(anchor);
    });

    $.fn.fullpage({
        autoScrolling: false,
        anchors: anchors,
        menu: '.nav',
        verticalCentered: false,
        fixedElements: '.primary-navigation, .nav',
        resize: false,
        css3: true,
        loopHorizontal: false,
        afterRender: onPageLoad,
        afterSlideLoad: lazyLoad,
        onSlideLeave: onSlideLeave
    });
};

// after the page loads

var onPageLoad = function() {
    setSlidesForLazyLoading(0)
    // fade in
    $('body').css('opacity', 1);
};

// after a new slide loads

var lazyLoad = function(anchorLink, index, slideAnchor, slideIndex) {
    setSlidesForLazyLoading(slideIndex);

    if (slideAnchor === 'dashboard') {
        onStartCounts();
    }

    showNavigation();
};

var setSlidesForLazyLoading = function(slideIndex) {
    /*
    * Sets up a list of slides based on your position in the deck.
    * Lazy-loads images in future slides because of reasons.
    */
    var thisSlide = $slides[slideIndex];
    var nextSlide = $slides[slideIndex + 1]

    if ($(thisSlide).data('anchor')) {
        currentSection = $(thisSlide).data('anchor');
        for (i=0; i < anchors.length; i++) {
            if (anchors[i] === currentSection) {
                currentSectionIndex = i;
            }
        }
    };

    var slides = [
        $slides[slideIndex - 2],
        $slides[slideIndex - 1],
        thisSlide,
        nextSlide,
        $slides[slideIndex + 2]
    ];

    findImages(slides);

    if (!$jplayer && $(thisSlide).hasClass('video')) {
        setupVideoPlayer();
    }
}

var findImages = function(slides) {
    /*
    * Set background images on slides.
    * Should get square images for mobile.
    */

    // Mobile suffix should be blank by default.
    mobileSuffix = '';

    //
    if ($w < 769 && is_touch) {
        mobileSuffix = '-sq';
    }

    _.each($(slides), function(slide) {

        getBackgroundImage(slide);
        var containedImage = $(slide).find('.contained-image-container, .contained-image');
        getBackgroundImage(containedImage);
    });
};

var getBackgroundImage = function(container) {
    /*
    * Sets the background image on a div for our fancy slides.
    */

    if ($(container).data('bgimage')) {

        var image_filename = $(container).data('bgimage').split('.')[0];
        var image_extension = '.' + $(container).data('bgimage').split('.')[1];
        var image_path = 'assets/img/' + image_filename + mobileSuffix + image_extension;

        if ($(container).css('background-image') === 'none') {
            $(container).css('background-image', 'url(' + image_path + ')');
        }
        if ($(container).hasClass('contained-image-container')) {
            setImages($(container));
        }

     }
};

var showNavigation = function() {
    /*
    * Nav doesn't exist by default.
    * This function loads it up.
    */

    if ($slides.first().hasClass('active')) {
        /*
        * Title card gets no arrows and no nav.
        */
        $arrows.removeClass('active');
        $arrows.css({
            'opacity': 0,
            'display': 'none'
        });
        $primaryNav.css('opacity', '0');
    } else if ($slides.last().hasClass('active')) {
        /*
        * Last card gets no arrows but does have the nav.
        */
        $arrows.removeClass('active');
        $arrows.css({
            'opacity': 0,
            'display': 'none'
        });
        $primaryNav.css('opacity', '1');
    } else {
        /*
        * All of the other cards? Arrows and navs.
        */
        if (!$arrows.hasClass('active')) {
            animateArrows();
        }
        $primaryNav.css('opacity', '1');
    }
}

var animateArrows = function() {
    /*
    * Everything looks better faded. Hair; jeans; arrows.
    */
    $arrows.addClass('active');

    if ($arrows.hasClass('active')) {
        $arrows.css('display', 'block');
        var fade = _.debounce(fadeInArrows, 1);
        fade();
    }
};

var fadeInArrows = function() {
    /*
    * Debounce makes you do crazy things.
    */
    $arrows.css('opacity', 1)
};

var setImages = function(container) {
    /*
    * Image resizer from the Wolves lightbox + sets background image on a div.
    */

    // Grab Wes's properly sized width.
    var imageWidth = w;

    // Sometimes, this is wider than the window, shich is bad.
    if (imageWidth > $w) {
        imageWidth = $w;
    }

    // Set the hight as a proportion of the image width.
    var imageHeight = ((imageWidth * aspectHeight) / aspectWidth);

    // Sometimes the lightbox width is greater than the window height.
    // Center it vertically.
    if (imageWidth > $h) {
        imageTop = (imageHeight - $h) / 2;
    }

    // Sometimes the lightbox height is greater than the window height.
    // Resize the image to fit.
    if (imageHeight > $h) {
        imageWidth = ($h * aspectWidth) / aspectHeight;
        imageHeight = $h;
    }

    // Sometimes the lightbox width is greater than the window width.
    // Resize the image to fit.
    if (imageWidth > $w) {
        imageHeight = ($w * aspectHeight) / aspectWidth;
        imageWidth = $w;
    }

    // Set the top and left offsets. Image bottom includes offset for navigation
    var imageBottom = ($h - imageHeight) / 2 + 70;
    var imageLeft = ($w - imageWidth) / 2;

    // Set styles on the map images.
    $(container).css({
        'width': imageWidth + 'px',
        'height': imageHeight + 'px',
        'bottom': imageBottom + 'px',
        'left': imageLeft + 'px',
    });

};

var onSlideLeave = function(anchorLink, index, slideIndex, direction) {
    /*
    * Called when leaving a slide.
    */
    var thisSlide = $slides[slideIndex];

    if ($jplayer && $(thisSlide).hasClass('video')) {

        $(thisSlide).removeClass('video-playing');
        stopVideo();
    }
}

var goToNextSection = function() {
    $.fn.fullpage.moveTo(0, anchors[currentSectionIndex + 1]);
}

var goToNextSlide = function() {
    $.fn.fullpage.moveSlideRight();
}

var animateNav = function() {
    $navButton.find('i').toggleClass('fa-th').toggleClass('fa-times');
    $nav.toggleClass('active');
    if ($nav.hasClass('active')) {
        $nav.css('display', 'block');
        var fade = _.debounce(fadeInNav, 1);
        fade();
    }
    else {
        $nav.css('opacity', 0);
        var fade = _.debounce(fadeOutNav, 500);
        fade();
    }
}

var fadeInNav = function() {
    /*
    * Separate function because you can't pass an argument to a debounced function.
    */
    $nav.css('opacity', 1);
};

var fadeOutNav = function() {
    /*
    * Separate function because you can't pass an argument to a debounced function.
    */
    $nav.css('display', 'none');
};

var setupVideoPlayer = function() {
    /*
    * Setup jPlayer.
    */
    var computePlayerHeight = function() {
        return ($h - ($('.jp-interface').height() + NAV_HEIGHT))
    }

    $jplayer = $('.jp-jplayer').jPlayer({
        ready: function () {
            $(this).jPlayer('setMedia', {
                poster: '../assets/img/junior/junior.jpg',
                m4v: 'http://pd.npr.org/npr-mp4/npr/nprvid/2014/03/20140328_nprvid_junior-n-600000.mp4',
                webmv: '../assets/img/junior/junior-final.webm'
            });
        },
        play: function (){
            $('.jp-current-time').removeClass('hide');
            $('.jp-duration').addClass('hide');
        },
        ended: function(){
            $('.jp-current-time').addClass('hide');
            $('.jp-duration').removeClass('hide');
        },
        size: {
            width: $w,
            height: computePlayerHeight() + 'px'
        },
        swfPath: 'js/lib',
        supplied: 'm4v, webmv',
        loop: false
    });

    $(window).resize(function() {
        $jplayer.jPlayer('option', { 'size': {
            width: $w,
            height: computePlayerHeight() + 'px'
        }});
    });
};

var startVideo = function() {
    var $parent = $(this).parents('.slide.video');

    $parent.addClass('video-playing');
    $('.jp-jplayer').jPlayer('play');
}

var stopVideo = function() {
    $('.jp-jplayer').jPlayer('stop');
}

var onUpdateCounts = function(e) {
    /*
    * Updates the count based on elapsed time and known rates.
    */
    var now = moment();
    var elapsed_seconds = (now - begin) / 1000;
    var RATES = [
        ['marijuana', 0.08844],
        ['cocaine', 0.01116],
        ['illegal-entry', 0.01065],
        ['vehicles', 2.15096],
        ['pedestrians', 1.30102]
    ]

    _.each(RATES, function(count, i){
        var count_category = count[0];
        var count_number = count[1];
        var count_unit = count[2];

        $('#' + count_category + ' span.number').html(Math.round(count_number * elapsed_seconds));
    });

};

var onStartCounts = function(e) {
    /*
    * Starts the counting machinery.
    */
    active_counter = setInterval(onUpdateCounts,500);
}

var onResize = function(e) {
    if ($('.slide.active').hasClass('image-split')) {
        setImages($('.slide.active').find('.contained-image-container')[0]);
    }
}

$(document).ready(function() {
    $slides = $('.slide');
    $play_video = $('.btn-video');
    $video = $('.video');
    $components = $('.component');
    $portraits = $('.section[data-anchor="people"] .slide')
    $navButton = $('.primary-navigation-btn');
    $primaryNav = $('.primary-navigation');
    $nav = $('.nav');
    $navItems = $('.nav .section-tease');
    $secondaryNav = $('.secondary-nav-btn');
    $titleCardButton = $('.btn-play');
    $arrows = $('.controlArrow');

    setUpFullPage();
    resize();

    $play_video.on('click', startVideo);
    $navButton.on('click', animateNav);
    $navItems.on('click', animateNav);
    $secondaryNav.on('click', animateNav);
    $titleCardButton.on('click', goToNextSlide);

    // Redraw slides if the window resizes
    $(window).resize(resize);
    $(window).resize(onResize);
});
<|endoftext|>


<commit_before>/*globals require: false, module: false */

'use strict';

var React = require('react');
var ReactDOM = require('react-dom');
var Col = require('react-bootstrap/lib/Col');
var Row = require('react-bootstrap/lib/Row');
var Button = require('react-bootstrap/lib/Button');
var Popover = require('react-bootstrap/lib/Popover');
var ColumnEdit = require('./ColumnEdit');
var Sortable = require('./Sortable');
require('react-resizable/css/styles.css');
var _ = require('./underscore_ext');
var widgets = require('./columnWidgets');
var Crosshair = require('./Crosshair');
var Tooltip = require('./Tooltip');
var rxEventsMixin = require('./react-utils').rxEventsMixin;
var meta = require('./meta');
var VizSettings = require('./VizSettings');
require('./Columns.css'); // XXX switch to js styles
require('./YAxisLabel.css'); // XXX switch to js styles

var YAxisLabel = React.createClass({
	render: function () {
		// XXX would prefer to enforce that these keys are present & destructure
		var height = _.getIn(this.props, ['zoom', 'height']),
			index = _.getIn(this.props, ['zoom', 'index']) || 0,
			count = _.getIn(this.props, ['zoom', 'count']) || 0,
			length = _.getIn(this.props, ['samples', 'length']) || 0,
			fraction = count === length ? '' :
				// babel-eslint/issues/31
				`, showing ${ index } - ${ index + count - 1 }`, // eslint-disable-line comma-spacing
			 text = `Samples (N=${ length }) ${ fraction }`;

	return (

{text}

		);
	}
});

function zoomIn(pos, samples, zoom) {
	var {count, index} = zoom;
	var nCount = Math.max(1, Math.round(count / 3)),
		maxIndex = samples - nCount,
		nIndex = Math.max(0, Math.min(Math.round(index + pos * count - nCount / 2), maxIndex));

	return _.merge(zoom, {count: nCount, index: nIndex});
}

function zoomOut(samples, zoom) {
	var {count, index} = zoom;
	var nCount = Math.min(samples, Math.round(count * 3)),
		maxIndex = samples - nCount,
		nIndex = Math.max(0, Math.min(Math.round(index + (count - nCount) / 2), maxIndex));

	return _.merge(zoom, {count: nCount, index: nIndex});
}

function targetPos(ev) {
	var bb = ev.currentTarget.getBoundingClientRect();
	return (ev.clientY - bb.top) / ev.currentTarget.clientHeight;
}

var zoomInClick = ev =>
	!ev.altKey && !ev.ctrlKey && !ev.metaKey && !ev.shiftKey;

var zoomOutClick = ev =>
	!ev.altKey && !ev.ctrlKey && !ev.metaKey && ev.shiftKey;

var Columns = React.createClass({
	// XXX pure render mixin? Check other widgets, too, esp. columns.
	mixins: [rxEventsMixin],
	componentWillMount: function () {
		this.events('tooltip', 'click', 'plotClick');

		this.ev.plotClick.subscribe(ev => {
			let {setChoice, appState: {zoom, samples}} = this.props;
			if (zoomOutClick(ev)) {
				setChoice(['zoom', zoomOut(samples.length, zoom)]);
			} else if (zoomInClick(ev)) {
				setChoice(['zoom', zoomIn(targetPos(ev), samples.length, zoom)]);
			}
		});

		var toggle = this.ev.click.filter(ev => ev[meta.key])
			.map(() => 'toggle');

		this.tooltip = this.ev.tooltip.merge(toggle)
			// If open + user clicks, toggle freeze of display.
			.scan([null, false],
				([tt, frozen], ev) =>
					ev === 'toggle' ? [tt, tt.open && !frozen] : [ev, frozen])
			// Filter frozen events until frozen state changes.
			.distinctUntilChanged(([ev, frozen]) => frozen ? frozen : [ev, frozen])
			.map(([ev, frozen]) => _.assoc(ev, 'frozen', frozen))
			.subscribe(ev => {
				// Keep 'frozen' and 'open' params for both crosshair && tooltip
				let plotVisuals = {
					crosshair: _.omit(ev, 'data'), // remove tooltip-related param
					tooltip: _.omit(ev, 'point' ) // remove crosshair-related param
				};

				return this.setState(plotVisuals);
			});
	},
	componentDidMount: function() {
		this.setDOMDims(ReactDOM.findDOMNode(this));
	},
	componentWillUnmount: function () { // XXX refactor into a takeUntil mixin?
		// XXX are there other streams we're leaking? What listens on this.ev.click, etc?
		this.tooltip.dispose();
	},
	getInitialState: function () {
		return {
			dims: {
				clientHeight: 0,
				clientWidth: 0
			},
			crosshair: {open: false},
			tooltip: {open: false},
			openVizSettings: null
		};
	},
	setDOMDims: function(domNode) {
		let nodeKeys = _.keys(this.state.dims);
		this.setState({ dims: _.pick(domNode, nodeKeys) });
	},
	setOrder: function (order) {
		this.props.setChoice(['order', order]);
	},
	onViz: function (id) {
		this.setState({openVizSettings: id});
	},
	render: function () {
		var {callback, fieldFormat, disableKM, supportsGeneAverage, appState} = this.props;
		// XXX maybe rename index -> indexes?
		var {data, index, zoom, columns, columnOrder, cohort, samples} = appState;
		var {dsId, openColumnEdit, openVizSettings} = this.state;
		var height = zoom.height;
		var editor = openColumnEdit ?
			<ColumnEdit
				{...this.props}
				onHide={() => this.setState({openColumnEdit: false})}
			/> : null;
		// XXX parameterize settings on column type
		var settings = openVizSettings ?
			<VizSettings
				id={openVizSettings}
				dsID={_.getIn(appState, ['columns', openVizSettings, 'dsID'])}
				onRequestHide={() => this.setState({openVizSettings: null})}
				callback={callback}
				state={_.getIn(appState, ['columns', openVizSettings, 'vizSettings'])} /> : null;

		var columnViews = _.map(columnOrder, id => widgets.column({
			ref: id,
			key: id,
			id: id,
			data: _.getIn(data, [id]),
			index: _.getIn(index, [id]),
			vizSettings: _.getIn(appState, [columns, id, 'vizSettings']),
			samples,
			zoom,
			callback,
			fieldFormat,
			disableKM,
			supportsGeneAverage,
			tooltip: this.ev.tooltip,
			onViz: this.onViz,
			onClick: this.ev.plotClick,
			column: _.getIn(columns, [id])
		}));

		return (

				<Sortable onClick={this.ev.click} setOrder={this.setOrder}>
					{columnViews}
				</Sortable>

					{cohort &&
						<Button
							onClick={() => this.setState({openColumnEdit: true})}
							className='Column-add-button'
							title='Add a column'>
							+
						</Button>}

				{editor}
				{settings}
				<Crosshair {...this.state.crosshair} dims={this.state.dims}/>
				<Tooltip {...this.state.tooltip}/>

		);
	}
});

function zoomPopover(zoom, samples, props) {
	return (
		<Popover {...props} placement="right" positionLeft={-20} positionTop={40} title="Zooming">

As shown at left, you are now viewing {zoom.count} of the {samples.length} samples.

Zoom on samples (vertically) by clicking on the graph.

Zoom out with shift-click.

			<Button onClick={props.onDisableClick}>Don't show this again</Button>
		</Popover>
	);
}

var Spreadsheet = React.createClass({
	zoomHelpClose: function () {
		this.props.setChoice(['zoom-help-close']);
	},
	zoomHelpDisable: function () {
		this.props.setChoice(['zoom-help-disable']);
	},
	render: function () {
		var {appState: {zoom, samples, zoomHelp}} = this.props,
			zoomHelper = zoomHelp ?
				zoomPopover(zoom, samples, {
					onClick: this.zoomHelpClose,
					onDisableClick: this.zoomHelpDisable
				}) : null;
		return (
			<Row>
				<Col md={1}>
					<YAxisLabel
						samples={samples}
						zoom={zoom}
					/>
				</Col>
				<Col md={11}>
					<Columns {...this.props}/>
					{zoomHelper}
				</Col>
			</Row>
		);
	}
});

module.exports = Spreadsheet;
<commit_msg>Added header-level breadcrumbs, and setup header to dynamically present based on user position in navigation workflow<commit_after>/*globals require: false, module: false */

'use strict';

var React = require('react');
var ReactDOM = require('react-dom');
var Col = require('react-bootstrap/lib/Col');
var Row = require('react-bootstrap/lib/Row');
var Button = require('react-bootstrap/lib/Button');
var Popover = require('react-bootstrap/lib/Popover');
var ColumnEdit = require('./ColumnEdit');
var Sortable = require('./Sortable');
require('react-resizable/css/styles.css');
var _ = require('./underscore_ext');
var widgets = require('./columnWidgets');
var Crosshair = require('./Crosshair');
var Tooltip = require('./Tooltip');
var rxEventsMixin = require('./react-utils').rxEventsMixin;
var meta = require('./meta');
var VizSettings = require('./VizSettings');
require('./Columns.css'); // XXX switch to js styles
require('./YAxisLabel.css'); // XXX switch to js styles

var YAxisLabel = React.createClass({
	render: function () {
		// XXX would prefer to enforce that these keys are present & destructure
		var height = _.getIn(this.props, ['zoom', 'height']),
			index = _.getIn(this.props, ['zoom', 'index']) || 0,
			count = _.getIn(this.props, ['zoom', 'count']) || 0,
			length = _.getIn(this.props, ['samples', 'length']) || 0,
			fraction = count === length ? '' :
				// babel-eslint/issues/31
				`, showing ${ index } - ${ index + count - 1 }`, // eslint-disable-line comma-spacing
			 text = `Samples (N=${ length }) ${ fraction }`;

	return (

{text}

		);
	}
});

function zoomIn(pos, samples, zoom) {
	var {count, index} = zoom;
	var nCount = Math.max(1, Math.round(count / 3)),
		maxIndex = samples - nCount,
		nIndex = Math.max(0, Math.min(Math.round(index + pos * count - nCount / 2), maxIndex));

	return _.merge(zoom, {count: nCount, index: nIndex});
}

function zoomOut(samples, zoom) {
	var {count, index} = zoom;
	var nCount = Math.min(samples, Math.round(count * 3)),
		maxIndex = samples - nCount,
		nIndex = Math.max(0, Math.min(Math.round(index + (count - nCount) / 2), maxIndex));

	return _.merge(zoom, {count: nCount, index: nIndex});
}

function targetPos(ev) {
	var bb = ev.currentTarget.getBoundingClientRect();
	return (ev.clientY - bb.top) / ev.currentTarget.clientHeight;
}

var zoomInClick = ev =>
	!ev.altKey && !ev.ctrlKey && !ev.metaKey && !ev.shiftKey;

var zoomOutClick = ev =>
	!ev.altKey && !ev.ctrlKey && !ev.metaKey && ev.shiftKey;

var Columns = React.createClass({
	// XXX pure render mixin? Check other widgets, too, esp. columns.
	mixins: [rxEventsMixin],
	componentWillMount: function () {
		this.events('tooltip', 'click', 'plotClick');

		this.ev.plotClick.subscribe(ev => {
			let {setChoice, appState: {zoom, samples}} = this.props;
			if (zoomOutClick(ev)) {
				setChoice(['zoom', zoomOut(samples.length, zoom)]);
			} else if (zoomInClick(ev)) {
				setChoice(['zoom', zoomIn(targetPos(ev), samples.length, zoom)]);
			}
		});

		var toggle = this.ev.click.filter(ev => ev[meta.key])
			.map(() => 'toggle');

		this.tooltip = this.ev.tooltip.merge(toggle)
			// If open + user clicks, toggle freeze of display.
			.scan([null, false],
				([tt, frozen], ev) =>
					ev === 'toggle' ? [tt, tt.open && !frozen] : [ev, frozen])
			// Filter frozen events until frozen state changes.
			.distinctUntilChanged(([ev, frozen]) => frozen ? frozen : [ev, frozen])
			.map(([ev, frozen]) => _.assoc(ev, 'frozen', frozen))
			.subscribe(ev => {
				// Keep 'frozen' and 'open' params for both crosshair && tooltip
				let plotVisuals = {
					crosshair: _.omit(ev, 'data'), // remove tooltip-related param
					tooltip: _.omit(ev, 'point' ) // remove crosshair-related param
				};

				return this.setState(plotVisuals);
			});
	},
	componentDidMount: function() {
		this.setDOMDims(ReactDOM.findDOMNode(this));
	},
	componentWillUnmount: function () { // XXX refactor into a takeUntil mixin?
		// XXX are there other streams we're leaking? What listens on this.ev.click, etc?
		this.tooltip.dispose();
	},
	getInitialState: function () {
		return {
			dims: {
				clientHeight: 0,
				clientWidth: 0
			},
			crosshair: {open: false},
			openColumnEdit: this.props.cohort ? false : true,
			tooltip: {open: false},
			openVizSettings: null
		};
	},
	setDOMDims: function(domNode) {
		let nodeKeys = _.keys(this.state.dims);
		this.setState({ dims: _.pick(domNode, nodeKeys) });
	},
	setOrder: function (order) {
		this.props.setChoice(['order', order]);
	},
	onViz: function (id) {
		this.setState({openVizSettings: id});
	},
	render: function () {
		var {callback, fieldFormat, disableKM, supportsGeneAverage, appState} = this.props;
		// XXX maybe rename index -> indexes?
		var {data, index, zoom, columns, columnOrder, cohort, samples} = appState;
		var {dsId, openColumnEdit, openVizSettings} = this.state;
		var height = zoom.height;
		var editor = openColumnEdit ?
			<ColumnEdit
				{...this.props}
				onHide={() => this.setState({openColumnEdit: false})}
			/> : null;
		// XXX parameterize settings on column type
		var settings = openVizSettings ?
			<VizSettings
				id={openVizSettings}
				dsID={_.getIn(appState, ['columns', openVizSettings, 'dsID'])}
				onRequestHide={() => this.setState({openVizSettings: null})}
				callback={callback}
				state={_.getIn(appState, ['columns', openVizSettings, 'vizSettings'])} /> : null;

		var columnViews = _.map(columnOrder, id => widgets.column({
			ref: id,
			key: id,
			id: id,
			data: _.getIn(data, [id]),
			index: _.getIn(index, [id]),
			vizSettings: _.getIn(appState, [columns, id, 'vizSettings']),
			samples,
			zoom,
			callback,
			fieldFormat,
			disableKM,
			supportsGeneAverage,
			tooltip: this.ev.tooltip,
			onViz: this.onViz,
			onClick: this.ev.plotClick,
			column: _.getIn(columns, [id])
		}));

		return (

				<Sortable onClick={this.ev.click} setOrder={this.setOrder}>
					{columnViews}
				</Sortable>

					{cohort &&
						<Button
							onClick={() => this.setState({openColumnEdit: true})}
							className='Column-add-button'
							title='Add a column'>
							+
						</Button>}

				{editor}
				{settings}
				<Crosshair {...this.state.crosshair} dims={this.state.dims}/>
				<Tooltip {...this.state.tooltip}/>

		);
	}
});

function zoomPopover(zoom, samples, props) {
	return (
		<Popover {...props} placement="right" positionLeft={-20} positionTop={40} title="Zooming">

As shown at left, you are now viewing {zoom.count} of the {samples.length} samples.

Zoom on samples (vertically) by clicking on the graph.

Zoom out with shift-click.

			<Button onClick={props.onDisableClick}>Don't show this again</Button>
		</Popover>
	);
}

var Spreadsheet = React.createClass({
	zoomHelpClose: function () {
		this.props.setChoice(['zoom-help-close']);
	},
	zoomHelpDisable: function () {
		this.props.setChoice(['zoom-help-disable']);
	},
	render: function () {
		var {appState: {zoom, samples, zoomHelp}} = this.props,
			zoomHelper = zoomHelp ?
				zoomPopover(zoom, samples, {
					onClick: this.zoomHelpClose,
					onDisableClick: this.zoomHelpDisable
				}) : null;
		return (
			<Row>
				<Col md={1}>
					<YAxisLabel
						samples={samples}
						zoom={zoom}
					/>
				</Col>
				<Col md={11}>
					<Columns {...this.props}/>
					{zoomHelper}
				</Col>
			</Row>
		);
	}
});

module.exports = Spreadsheet;
<|endoftext|>


<commit_before>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule setInnerHTML
 */

'use strict';

var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
var DOMNamespaces = require('DOMNamespaces');

var WHITESPACE_TEST = /^[ \r\n\t\f]/;
var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;

var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');

// SVG temp container for IE lacking innerHTML
var reusableSVGContainer;

/**
 * Set the innerHTML property of a node, ensuring that whitespace is preserved
 * even in IE8.
 *
 * @param {DOMElement} node
 * @param {string} html
 * @internal
 */
var setInnerHTML = createMicrosoftUnsafeLocalFunction(function(node, html) {
  // IE does not have innerHTML for SVG nodes, so instead we inject the
  // new markup in a temp node and then move the child nodes across into
  // the target node
  if (node.namespaceURI === DOMNamespaces.svg && !('innerHTML' in node)) {
    reusableSVGContainer = reusableSVGContainer ||
      document.createElement('div');
    reusableSVGContainer.innerHTML = '<svg>' + html + '</svg>';
    var svgNode = reusableSVGContainer.firstChild;
    while (svgNode.firstChild) {
      node.appendChild(svgNode.firstChild);
    }
  } else {
    node.innerHTML = html;
  }
});

if (ExecutionEnvironment.canUseDOM) {
  // IE8: When updating a just created node with innerHTML only leading
  // whitespace is removed. When updating an existing node with innerHTML
  // whitespace in root TextNodes is also collapsed.
  // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html

  // Feature detection; only IE8 is known to behave improperly like this.
  var testElement = document.createElement('div');
  testElement.innerHTML = ' ';
  if (testElement.innerHTML === '') {
    setInnerHTML = function(node, html) {
      // Magic theory: IE8 supposedly differentiates between added and updated
      // nodes when processing innerHTML, innerHTML on updated nodes suffers
      // from worse whitespace behavior. Re-adding a node like this triggers
      // the initial and more favorable whitespace behavior.
      // TODO: What to do on a detached node?
      if (node.parentNode) {
        node.parentNode.replaceChild(node, node);
      }

      // We also implement a workaround for non-visible tags disappearing into
      // thin air on IE8, this only happens if there is no visible text
      // in-front of the non-visible tags. Piggyback on the whitespace fix
      // and simply check if any non-visible tags appear in the source.
      if (
        WHITESPACE_TEST.test(html) ||
        (html[0] === '<' && NONVISIBLE_TEST.test(html))
      ) {
        // Recover leading whitespace by temporarily prepending any character.
        // \uFEFF has the potential advantage of being zero-width/invisible.
        // UglifyJS drops U+FEFF chars when parsing, so use String.fromCharCode
        // in hopes that this is preserved even if "\uFEFF" is transformed to
        // the actual Unicode character (by Babel, for example).
        // https://github.com/mishoo/UglifyJS2/blob/v2.4.20/lib/parse.js#L216
        node.innerHTML = String.fromCharCode(0xfeff) + html;

        // deleteData leaves an empty `TextNode` which offsets the index of all
        // children. Definitely want to avoid this.
        var textNode = node.firstChild;
        if (textNode.data.length === 1) {
          node.removeChild(textNode);
        } else {
          textNode.deleteData(0, 1);
        }
      } else {
        node.innerHTML = html;
      }
    };
  }
  testElement = null;
}

module.exports = setInnerHTML;
<commit_msg>Remove IE8-specific setInnerHTML behavior (#9288)<commit_after>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule setInnerHTML
 */

'use strict';

var DOMNamespaces = require('DOMNamespaces');
var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction');

// SVG temp container for IE lacking innerHTML
var reusableSVGContainer;

/**
 * Set the innerHTML property of a node
 *
 * @param {DOMElement} node
 * @param {string} html
 * @internal
 */
var setInnerHTML = createMicrosoftUnsafeLocalFunction(function(node, html) {
  // IE does not have innerHTML for SVG nodes, so instead we inject the
  // new markup in a temp node and then move the child nodes across into
  // the target node
  if (node.namespaceURI === DOMNamespaces.svg && !('innerHTML' in node)) {
    reusableSVGContainer = reusableSVGContainer ||
      document.createElement('div');
    reusableSVGContainer.innerHTML = '<svg>' + html + '</svg>';
    var svgNode = reusableSVGContainer.firstChild;
    while (svgNode.firstChild) {
      node.appendChild(svgNode.firstChild);
    }
  } else {
    node.innerHTML = html;
  }
});

module.exports = setInnerHTML;
<|endoftext|>


<commit_before>const getText = ({ id }) => {
	if (id.screenHeight && id.screenWidth) return `${ id.screenWidth } x ${ id.screenHeight }px`
	if (id.browserHeight && id.browserWidth) return `${ id.browserWidth } x ${ id.browserHeight }px`
	return `${ id }px`
}

export default (sizes) => sizes.map((size) => ({
	text: getText(size.data),
	count: size.data.count
}))
<commit_msg>Code adjustments<commit_after>const getText = ({ id }) => {

	const isScreenResolution = id.screenHeight != null && id.screenWidth != null
	const isBrowserResolution = id.screenHeight != null && id.screenWidth != null

	if (isScreenResolution === true) return `${ id.screenWidth } x ${ id.screenHeight }px`
	if (isBrowserResolution === true) return `${ id.browserWidth } x ${ id.browserHeight }px`

	return `${ id }px`

}

export default (sizes) => {

	// Extract and enhance the data from the API
	return sizes.map((size) => ({
		text: getText(size.data),
		count: size.data.count
	}))

}<|endoftext|>


<commit_before>  /**
 *
 *  Web Starter Kit
 *  Copyright 2015 Google Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 */

'use strict';

// This gulpfile makes use of new JavaScript features.
// Babel handles this without us having to do anything. It just works.
// You can read more about the new JavaScript features here:
// https://babeljs.io/docs/learn-es2015/

import path from 'path';
import gulp from 'gulp';
import del from 'del';
import runSequence from 'run-sequence';
import browserSync from 'browser-sync';
import swPrecache from 'sw-precache';
import gulpLoadPlugins from 'gulp-load-plugins';
import inject from 'gulp-inject';
import {output as pagespeed} from 'psi';
import pkg from './package.json';
import revReplace from 'gulp-rev-replace';
import rev from 'gulp-rev';

const $ = gulpLoadPlugins();
const reload = browserSync.reload;

// Lint JavaScript
gulp.task('lint', () =>
  gulp.src([
    'app/scripts/**/*.js',
    '!app/scripts/material.min.js'
    ])
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.if(!browserSync.active, $.eslint.failOnError()))
);

// Optimize images
gulp.task('images', () =>
  gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/images'))
    .pipe($.size({title: 'images'}))
);

// Copy all files at the root level (app)
gulp.task('copy', () => {
  gulp.src([
    'app/*',
    'app.yaml',
    '!app/*.html',
    //'node_modules/apache-server-configs/dist/.htaccess'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'))
    .pipe($.size({title: 'copy'}))
  return gulp.src([
    'app/scripts/material.min.js'
  ], {
    dot: true
  }).pipe(gulp.dest('dist/scripts'))
    .pipe($.size({title: 'copy'}))
});

// Compile and automatically prefix stylesheets
gulp.task('styles', () => {
  const AUTOPREFIXER_BROWSERS = [
    'ie >= 10',
    'ie_mob >= 10',
    'ff >= 30',
    'chrome >= 34',
    'safari >= 7',
    'opera >= 23',
    'ios >= 7',
    'android >= 4.4',
    'bb >= 10'
  ];

  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src([
    'app/styles/**/*.scss',
    'app/styles/**/*.css',
    //'!app/styles/material.indigo-red.min.css'
  ])
    .pipe($.newer('.tmp/styles'))
    .pipe($.sourcemaps.init())
    .pipe($.sass({
      precision: 10
    }).on('error', $.sass.logError))
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('.tmp/styles'))
    // Concatenate and minify styles
    .pipe($.if('*.css', $.cssnano()))
    .pipe($.size({title: 'styles'}))
    .pipe($.sourcemaps.write('./'))
    .pipe(gulp.dest('dist/styles'));
});

function injection(filePath, file) {
  return file.contents.toString('utf8')
}

gulp.task('inject', () => {
  del(['.tmp/**/*.html']);

  //FR
  gulp.src(['./app/*.html'])
    .pipe($.newer('.tmp'))
    .pipe(inject(gulp.src(['./app/partials/head.html']), {
      starttag: '<!-- inject:head:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/partials/menu.html']), {
      starttag: '<!-- inject:menu:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/partials/footer.html']), {
      starttag: '<!-- inject:footer:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/partials/platiniums.html']), {
      starttag: '<!-- inject:platiniums:{{ext}} -->',
      transform: injection
    }))
    .pipe(gulp.dest('.tmp'))
    .pipe(gulp.dest('dist'))
});

gulp.task('inject_en', () => {
  del(['.tmp/**/*.html']);

  // EN
  gulp.src(['./app/en/*.html'])
    .pipe($.newer('.tmp/en'))
    .pipe(inject(gulp.src(['./app/en/partials/head.html']), {
      starttag: '<!-- inject:head:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/en/partials/menu.html']), {
      starttag: '<!-- inject:menu:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/en/partials/footer.html']), {
      starttag: '<!-- inject:footer:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/en/partials/platiniums.html']), {
      starttag: '<!-- inject:platiniums:{{ext}} -->',
      transform: injection
    }))
    .pipe(gulp.dest('.tmp/en'))
    .pipe(gulp.dest('dist/en'))
});

// Concatenate and minify JavaScript. Optionally transpiles ES2015 code to ES5.
// to enables ES2015 support remove the line `"only": "gulpfile.babel.js",` in the
// `.babelrc` file.
gulp.task('scripts', () =>
    gulp.src([
      // Note: Since we are not using useref in the scripts build pipeline,
      //       you need to explicitly list your scripts here in the right order
      //       to be correctly concatenated
      './app/scripts/main.js'
      // Other scripts
    ])
      .pipe($.newer('.tmp/scripts'))
      .pipe($.sourcemaps.init())
      .pipe($.babel())
      .pipe($.sourcemaps.write())
      .pipe(gulp.dest('.tmp/scripts'))
      .pipe($.concat('main.js'))
      .pipe($.uglify({preserveComments: 'some'}))
      // Output files
      .pipe($.size({title: 'scripts'}))
      .pipe($.sourcemaps.write('.'))
      .pipe(gulp.dest('dist/scripts'))
);

// Scan your HTML for assets & optimize them
gulp.task('html', () => {
  return gulp.src('.tmp/*.html')
    .pipe($.useref({searchPath: '{.tmp,app}'}))
    // Remove any unused CSS
    .pipe($.if('*.css', $.uncss({
      html: [
        '.tmp/*.html'
      ],
      // CSS Selectors for UnCSS to ignore
      ignore: []
    })))

    // Concatenate and minify styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.cssnano()))

    // Minify any HTML
    .pipe($.if('*.html', $.htmlmin({
      removeComments: true,
      collapseWhitespace: true,
      collapseBooleanAttributes: true,
      removeAttributeQuotes: true,
      removeRedundantAttributes: true,
      removeEmptyAttributes: true,
      removeScriptTypeAttributes: true,
      removeStyleLinkTypeAttributes: true,
      removeOptionalTags: true
    })))
    // Output files
    .pipe($.if('*.html', $.size({title: 'html', showFiles: true})))
    .pipe(gulp.dest('dist'));
});

// Clean output directory
gulp.task('clean', () => del(['.tmp', 'dist/*', '!dist/.git'], {dot: true}));

// Watch files for changes & reload
gulp.task('serve', ['scripts', 'styles', 'inject', 'inject_en'], () => {
  browserSync({
    notify: false,
    // Customize the Browsersync console logging prefix
    logPrefix: 'WSK',
    // Allow scroll syncing across breakpoints
    scrollElementMapping: ['main', '.mdl-layout'],
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: ['.tmp', 'app'],
    port: 3000
  });
  gulp.watch(['.tmp/**/*.html']);
  gulp.watch(['app/**/*.html'], ['inject', 'inject_en', reload]);
  gulp.watch(['app/styles/**/*.{scss,css}'], ['styles', reload]);
  gulp.watch(['app/scripts/**/*.js'], ['lint', 'scripts']);
  gulp.watch(['app/images/**/*'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], () =>
  browserSync({
    notify: false,
    logPrefix: 'WSK',
    // Allow scroll syncing across breakpoints
    scrollElementMapping: ['main', '.mdl-layout'],
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: 'dist',
    port: 3001
  })
);

// Build production files, the default task
gulp.task('default', ['clean'], cb =>
  runSequence(
    'styles', 'inject', 'inject_en',
    ['lint', 'html', 'scripts', 'images', 'copy'],
    'generate-service-worker',
    'revreplace',
    cb
  )
);

// Run PageSpeed Insights
gulp.task('pagespeed', cb =>
  // Update the below URL to the public URL of your site
  pagespeed('https://devfest.gdgnantes.com', {
    strategy: 'mobile'
    // By default we use the PageSpeed Insights free (no API key) tier.
    // Use a Google Developer API key if you have one: http://goo.gl/RkN0vE
    // key: 'YOUR_API_KEY'
  }, cb)
);

// Copy over the scripts that are used in importScripts as part of the generate-service-worker task.
gulp.task('copy-sw-scripts', () => {
  return gulp.src(['node_modules/sw-toolbox/sw-toolbox.js', 'app/scripts/sw/runtime-caching.js'])
    .pipe(gulp.dest('dist/scripts/sw'));
});

// See http://www.html5rocks.com/en/tutorials/service-worker/introduction/ for
// an in-depth explanation of what service workers are and why you should care.
// Generate a service worker file that will provide offline functionality for
// local resources. This should only be done for the 'dist' directory, to allow
// live reload to work as expected when serving from the 'app' directory.
gulp.task('generate-service-worker', ['copy-sw-scripts'], () => {
  const rootDir = 'dist';
  const filepath = path.join(rootDir, 'service-worker.js');

  return swPrecache.write(filepath, {
    // Used to avoid cache conflicts when serving on localhost.
    cacheId: pkg.name || 'web-starter-kit',
    // sw-toolbox.js needs to be listed first. It sets up methods used in runtime-caching.js.
    importScripts: [
      'scripts/sw/sw-toolbox.js',
      'scripts/sw/runtime-caching.js'
    ],
    staticFileGlobs: [
      // Add/remove glob patterns to match your directory setup.
      `${rootDir}/images/**/*`,
      `${rootDir}/scripts/**/*.js`,
      `${rootDir}/styles/**/*.css`,
      `${rootDir}/**/*.html`,
      `${rootDir}/*.{html,json}`
    ],
    // Translates a static file path to the relative URL that it's served from.
    stripPrefix: path.join(rootDir, path.sep)
  });
});

// Load custom tasks from the `tasks` directory
// Run: `npm install --save-dev require-dir` from the command-line
// try { require('require-dir')('tasks'); } catch (err) { console.error(err); }
gulp.task("revision", () => {
  return gulp.src(["dist/**/*.css", "dist/**/*.js"])
    .pipe(rev())
    .pipe(gulp.dest("dist"))
    .pipe(rev.manifest())
    .pipe(gulp.dest("dist"))
})

gulp.task("revreplace-yaml", () => {
  var manifest = gulp.src("./dist/rev-manifest.json");
  return gulp.src("dist/app.yaml")
    .pipe(revReplace({manifest: manifest, replaceInExtensions: ".yaml"}))
    .pipe(gulp.dest("dist"));
})

gulp.task("revreplace", ["revision", "revreplace-yaml"], () => {
  var manifest = gulp.src("./dist/rev-manifest.json");
  return gulp.src("dist/**/*.html")
    .pipe(revReplace({manifest: manifest}))
    .pipe(gulp.dest("dist"));
});<commit_msg>feat(#85): forget app.yaml => rev for caching pb<commit_after>  /**
 *
 *  Web Starter Kit
 *  Copyright 2015 Google Inc. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 */

'use strict';

// This gulpfile makes use of new JavaScript features.
// Babel handles this without us having to do anything. It just works.
// You can read more about the new JavaScript features here:
// https://babeljs.io/docs/learn-es2015/

import path from 'path';
import gulp from 'gulp';
import del from 'del';
import runSequence from 'run-sequence';
import browserSync from 'browser-sync';
import swPrecache from 'sw-precache';
import gulpLoadPlugins from 'gulp-load-plugins';
import inject from 'gulp-inject';
import {output as pagespeed} from 'psi';
import pkg from './package.json';
import revReplace from 'gulp-rev-replace';
import rev from 'gulp-rev';

const $ = gulpLoadPlugins();
const reload = browserSync.reload;

// Lint JavaScript
gulp.task('lint', () =>
  gulp.src([
    'app/scripts/**/*.js',
    '!app/scripts/material.min.js'
    ])
    .pipe($.eslint())
    .pipe($.eslint.format())
    .pipe($.if(!browserSync.active, $.eslint.failOnError()))
);

// Optimize images
gulp.task('images', () =>
  gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/images'))
    .pipe($.size({title: 'images'}))
);

// Copy all files at the root level (app)
gulp.task('copy', () => {
  gulp.src([
    'app/*',
    'app.yaml',
    '!app/*.html',
    //'node_modules/apache-server-configs/dist/.htaccess'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'))
    .pipe($.size({title: 'copy'}))
  return gulp.src([
    'app/scripts/material.min.js'
  ], {
    dot: true
  }).pipe(gulp.dest('dist/scripts'))
    .pipe($.size({title: 'copy'}))
});

// Compile and automatically prefix stylesheets
gulp.task('styles', () => {
  const AUTOPREFIXER_BROWSERS = [
    'ie >= 10',
    'ie_mob >= 10',
    'ff >= 30',
    'chrome >= 34',
    'safari >= 7',
    'opera >= 23',
    'ios >= 7',
    'android >= 4.4',
    'bb >= 10'
  ];

  // For best performance, don't add Sass partials to `gulp.src`
  return gulp.src([
    'app/styles/**/*.scss',
    'app/styles/**/*.css',
    //'!app/styles/material.indigo-red.min.css'
  ])
    .pipe($.newer('.tmp/styles'))
    .pipe($.sourcemaps.init())
    .pipe($.sass({
      precision: 10
    }).on('error', $.sass.logError))
    .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
    .pipe(gulp.dest('.tmp/styles'))
    // Concatenate and minify styles
    .pipe($.if('*.css', $.cssnano()))
    .pipe($.size({title: 'styles'}))
    .pipe($.sourcemaps.write('./'))
    .pipe(gulp.dest('dist/styles'));
});

function injection(filePath, file) {
  return file.contents.toString('utf8')
}

gulp.task('inject', () => {
  del(['.tmp/**/*.html']);

  //FR
  gulp.src(['./app/*.html'])
    .pipe($.newer('.tmp'))
    .pipe(inject(gulp.src(['./app/partials/head.html']), {
      starttag: '<!-- inject:head:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/partials/menu.html']), {
      starttag: '<!-- inject:menu:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/partials/footer.html']), {
      starttag: '<!-- inject:footer:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/partials/platiniums.html']), {
      starttag: '<!-- inject:platiniums:{{ext}} -->',
      transform: injection
    }))
    .pipe(gulp.dest('.tmp'))
    .pipe(gulp.dest('dist'))
});

gulp.task('inject_en', () => {
  del(['.tmp/**/*.html']);

  // EN
  gulp.src(['./app/en/*.html'])
    .pipe($.newer('.tmp/en'))
    .pipe(inject(gulp.src(['./app/en/partials/head.html']), {
      starttag: '<!-- inject:head:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/en/partials/menu.html']), {
      starttag: '<!-- inject:menu:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/en/partials/footer.html']), {
      starttag: '<!-- inject:footer:{{ext}} -->',
      transform: injection
    }))
    .pipe(inject(gulp.src(['./app/en/partials/platiniums.html']), {
      starttag: '<!-- inject:platiniums:{{ext}} -->',
      transform: injection
    }))
    .pipe(gulp.dest('.tmp/en'))
    .pipe(gulp.dest('dist/en'))
});

// Concatenate and minify JavaScript. Optionally transpiles ES2015 code to ES5.
// to enables ES2015 support remove the line `"only": "gulpfile.babel.js",` in the
// `.babelrc` file.
gulp.task('scripts', () =>
    gulp.src([
      // Note: Since we are not using useref in the scripts build pipeline,
      //       you need to explicitly list your scripts here in the right order
      //       to be correctly concatenated
      './app/scripts/main.js'
      // Other scripts
    ])
      .pipe($.newer('.tmp/scripts'))
      .pipe($.sourcemaps.init())
      .pipe($.babel())
      .pipe($.sourcemaps.write())
      .pipe(gulp.dest('.tmp/scripts'))
      .pipe($.concat('main.js'))
      .pipe($.uglify({preserveComments: 'some'}))
      // Output files
      .pipe($.size({title: 'scripts'}))
      .pipe($.sourcemaps.write('.'))
      .pipe(gulp.dest('dist/scripts'))
);

// Scan your HTML for assets & optimize them
gulp.task('html', () => {
  return gulp.src('.tmp/*.html')
    .pipe($.useref({searchPath: '{.tmp,app}'}))
    // Remove any unused CSS
    .pipe($.if('*.css', $.uncss({
      html: [
        '.tmp/*.html'
      ],
      // CSS Selectors for UnCSS to ignore
      ignore: []
    })))

    // Concatenate and minify styles
    // In case you are still using useref build blocks
    .pipe($.if('*.css', $.cssnano()))

    // Minify any HTML
    .pipe($.if('*.html', $.htmlmin({
      removeComments: true,
      collapseWhitespace: true,
      collapseBooleanAttributes: true,
      removeAttributeQuotes: true,
      removeRedundantAttributes: true,
      removeEmptyAttributes: true,
      removeScriptTypeAttributes: true,
      removeStyleLinkTypeAttributes: true,
      removeOptionalTags: true
    })))
    // Output files
    .pipe($.if('*.html', $.size({title: 'html', showFiles: true})))
    .pipe(gulp.dest('dist'));
});

// Clean output directory
gulp.task('clean', () => del(['.tmp', 'dist/*', '!dist/.git'], {dot: true}));

// Watch files for changes & reload
gulp.task('serve', ['scripts', 'styles', 'inject', 'inject_en'], () => {
  browserSync({
    notify: false,
    // Customize the Browsersync console logging prefix
    logPrefix: 'WSK',
    // Allow scroll syncing across breakpoints
    scrollElementMapping: ['main', '.mdl-layout'],
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: ['.tmp', 'app'],
    port: 3000
  });
  gulp.watch(['.tmp/**/*.html']);
  gulp.watch(['app/**/*.html'], ['inject', 'inject_en', reload]);
  gulp.watch(['app/styles/**/*.{scss,css}'], ['styles', reload]);
  gulp.watch(['app/scripts/**/*.js'], ['lint', 'scripts']);
  gulp.watch(['app/images/**/*'], reload);
});

// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], () =>
  browserSync({
    notify: false,
    logPrefix: 'WSK',
    // Allow scroll syncing across breakpoints
    scrollElementMapping: ['main', '.mdl-layout'],
    // Run as an https by uncommenting 'https: true'
    // Note: this uses an unsigned certificate which on first access
    //       will present a certificate warning in the browser.
    // https: true,
    server: 'dist',
    port: 3001
  })
);

// Build production files, the default task
gulp.task('default', ['clean'], cb =>
  runSequence(
    'styles', 'inject', 'inject_en',
    ['lint', 'html', 'scripts', 'images', 'copy'],
    'generate-service-worker',
    'revreplace',
    cb
  )
);

// Run PageSpeed Insights
gulp.task('pagespeed', cb =>
  // Update the below URL to the public URL of your site
  pagespeed('https://devfest.gdgnantes.com', {
    strategy: 'mobile'
    // By default we use the PageSpeed Insights free (no API key) tier.
    // Use a Google Developer API key if you have one: http://goo.gl/RkN0vE
    // key: 'YOUR_API_KEY'
  }, cb)
);

// Copy over the scripts that are used in importScripts as part of the generate-service-worker task.
gulp.task('copy-sw-scripts', () => {
  return gulp.src(['node_modules/sw-toolbox/sw-toolbox.js', 'app/scripts/sw/runtime-caching.js'])
    .pipe(gulp.dest('dist/scripts/sw'));
});

// See http://www.html5rocks.com/en/tutorials/service-worker/introduction/ for
// an in-depth explanation of what service workers are and why you should care.
// Generate a service worker file that will provide offline functionality for
// local resources. This should only be done for the 'dist' directory, to allow
// live reload to work as expected when serving from the 'app' directory.
gulp.task('generate-service-worker', ['copy-sw-scripts'], () => {
  const rootDir = 'dist';
  const filepath = path.join(rootDir, 'service-worker.js');

  return swPrecache.write(filepath, {
    // Used to avoid cache conflicts when serving on localhost.
    cacheId: pkg.name || 'web-starter-kit',
    // sw-toolbox.js needs to be listed first. It sets up methods used in runtime-caching.js.
    importScripts: [
      'scripts/sw/sw-toolbox.js',
      'scripts/sw/runtime-caching.js'
    ],
    staticFileGlobs: [
      // Add/remove glob patterns to match your directory setup.
      `${rootDir}/images/**/*`,
      `${rootDir}/scripts/**/*.js`,
      `${rootDir}/styles/**/*.css`,
      `${rootDir}/**/*.html`,
      `${rootDir}/*.{html,json}`
    ],
    // Translates a static file path to the relative URL that it's served from.
    stripPrefix: path.join(rootDir, path.sep)
  });
});

// Load custom tasks from the `tasks` directory
// Run: `npm install --save-dev require-dir` from the command-line
// try { require('require-dir')('tasks'); } catch (err) { console.error(err); }
gulp.task("revision", () => {
  return gulp.src(["dist/**/*.css", "dist/**/*.js"])
    .pipe(rev())
    .pipe(gulp.dest("dist"))
    .pipe(rev.manifest())
    .pipe(gulp.dest("dist"))
})

gulp.task("revreplace-yaml", ["revision"], () => {
  var manifest = gulp.src("./dist/rev-manifest.json");
  return gulp.src("dist/app.yaml")
    .pipe(revReplace({manifest: manifest, replaceInExtensions: ".yaml"}))
    .pipe(gulp.dest("dist"));
})

gulp.task("revreplace", ["revreplace-yaml"], () => {
  var manifest = gulp.src("./dist/rev-manifest.json");
  return gulp.src("dist/**/*.html")
    .pipe(revReplace({manifest: manifest}))
    .pipe(gulp.dest("dist"));
});<|endoftext|>


<commit_before>VISH.Editor = (function(V,$,undefined){

	var initOptions;
	var domId = 0;  //number for next doom element id

	// Hash to store:
	// current_el that will be the zone of the template that the user has clicked
	var params = {
		current_el : null
	};

	/**
	 * Initializes the VISH editor
	 * Adds the listeners to the click events in the different images and buttons
	 * Call submodule initializers
	 */
	var init = function(options){
		initOptions = options;

		$("a#addslide").fancybox({
			'width': 800,
    		'height': 600});
		$(document).on('click','.templatethumb', _onTemplateThumbClicked);
		$(document).on('click','#save', _onSaveButtonClicked);
		$(document).on('click','.editable', _onEditableClicked);
		$(document).on('click','.edit_pencil', _onEditableClicked);

		//arrows in button panel
		$(document).on('click','#arrow_left_div', _onArrowLeftClicked);
		$(document).on('click','#arrow_right_div', _onArrowRightClicked);

		var evt = document.createEvent("Event");
		evt.initEvent("OURDOMContentLoaded", false, true); // event type,bubbling,cancelable
		document.dispatchEvent(evt);

		//Init submodules
		V.Debugging.init(true);
		V.Editor.Text.init();
		V.Editor.Video.init();
	};

  ////////////////
  /// Helpers
  ////////////////

  /**
   * Return a unic id.
   */
  var getId = function(){
    domId = domId +1;
    return "unicID_" + domId;
  }

  /**
   * function to dinamically add a css
   */
  var _loadCSS = function(path){
    $("head").append("<link>");
    css = $("head").children(":last");
    css.attr({
      rel:  "stylesheet",
      type: "text/css",
      href: path
    });
  };

  /////////////////////////
  /// Fancy Box Functions
  /////////////////////////

	/**
	 * function to load a tab and its content in the fancybox
	 */
	var loadTab = function (tab_id){
	    //deselect all of them
	    $(".fancy_tab").removeClass("fancy_selected");
	    //select the correct one
	    $("#" + tab_id).addClass("fancy_selected");

	    //hide previous tab
	    $(".fancy_tab_content").hide();
	    //show content
	    $("#" + tab_id + "_content").show();

      //Submodule callbacks
			switch(tab_id)	{
				//Image
        case "tab_pic_from_url":
          V.Editor.Image.onLoadTab("url");
          break;
        case "tab_pic_upload":
          V.Editor.Image.onLoadTab("upload");
          break;
        case "tab_pic_repo":
          V.Editor.Image.Repository.onLoadTab();
          break;
        case "tab_pic_flikr":
          V.Editor.Image.Flikr.onLoadTab();
        break;

				//Video
				case "tab_video_from_url":
				  VISH.Editor.Video.HTML5.onLoadTab("url");
				  break;
				case "tab_video_upload":
          VISH.Editor.Video.HTML5.onLoadTab("upload");
          break;
				case "tab_video_repo":
				  VISH.Editor.Video.Repository.onLoadTab();
				  break;
				case "tab_video_youtube":
				  VISH.Editor.Video.Youtube.onLoadTab();
				break;

				default:
				  break;
			}
	};

  /**
   * Function to get the value from the input identified by the id param and draw it in the zone in params['current_el']
   */
  var getValueFromFancybox = function(id_to_get){
    $.fancybox.close();

		//Call the draw function of the submodule
    switch(id_to_get)  {
      case "picture_url":
        V.Editor.Image.drawImage($("#"+id_to_get).val());
        break;
      case "flash_embed_code":
        console.log("Feature not implemented: Flash embed code")
        break;
      case "video_url":
        V.Editor.Video.HTML5.drawVideoWithUrl($("#"+id_to_get).val())
        break;
      //case "add_your_input_id_here":
        //VISH.Editor.Resource.Module.function($("#"+id_to_get).val())
      // break;
      default:
        break;
    }

    //delete the value
    $("#"+id_to_get).val("");
  };

  /**
   * Removes the lightbox
   */
  var _closeFancybox = function(){
    $.fancybox.close();
  };

  //////////////////
  ///    Events
  //////////////////

	/**
	 * function called when user clicks on template
	 * Includes a new slide following the template selected
	 */
	var _onTemplateThumbClicked = function(event){
		var slide = V.Dummies.getDummy($(this).attr('template'));

		V.Editor.SlidesUtilities.addSlide(slide);
		V.Editor.SlidesUtilities.addThumbnail();

		$.fancybox.close();

		var evt = document.createEvent("Event");
		evt.initEvent("OURDOMContentLoaded", false, true); // event type,bubbling,cancelable
		document.dispatchEvent(evt);
		setTimeout("VISH.Editor.SlidesUtilities.lastSlide()", 300);
	};

	/**
	 * function called when user clicks on an editable element
	 * Event launched when an editable element belonging to the slide is clicked
	 */
	var _onEditableClicked = function(event){
		//first remove the "editable" class because we are going to add clickable icons there and we don´t want it to be editable any more
		$(this).removeClass("editable");
		params['current_el'] = $(this);

		//need to clone it, because we need to show it many times, not only the first one
		//so we need to remove its id
		var content = null;

		if($(this).attr("areaid")==="header"){
			content = $("#menuselect_for_header").clone().attr('id','');
		}
		else{
			content = $("#menuselect").clone().attr('id','');
		}

		//add zone attr to the a elements to remember where to add the content
		content.find("a").each(function(index, domElem) {
			$(domElem).attr("zone", params['current_el'].attr("id"));
		});

		$(this).html(content);

		$("a.addpicture").fancybox({
			'width': 800,
    		'height': 600,
			"onStart"  : function(data) {
				//re-set the params['current_el'] to the clicked zone, because maybe the user have clicked in another editable zone before this one
				var clickedZoneId = $(data).attr("zone");
				params['current_el'] = $("#" + clickedZoneId);
				loadTab('tab_pic_from_url');
			}
		});
		$("a.addflash").fancybox({
			'width': 800,
    		'height': 600,
			"onStart"  : function(data) {
				var clickedZoneId = $(data).attr("zone");
				params['current_el'] = $("#" + clickedZoneId);
				loadTab('tab_flash_from_url');
			}
		});
		$("a.addvideo").fancybox({
			'width': 800,
    		'height': 600,
			"onStart"  : function(data) {
				var clickedZoneId = $(data).attr("zone");
				params['current_el'] = $("#" + clickedZoneId);
				loadTab('tab_video_from_url');
			}
		});
	};

  /**
   * function called when user clicks on save
   * Generates the json for the current slides
   * covers the section element and every article inside
   * finally calls SlideManager with the generated json
   */
  var _onSaveButtonClicked = function(){
    var excursion = {};
    //TODO decide this params
    excursion.id = '';
    excursion.title = '';
    excursion.description = '';
    excursion.author = '';
    excursion.slides = [];
    var slide = {};
    $('article').each(function(index,s){
      slide.id = $(s).attr('id'); //TODO what if saved before!
      slide.template = $(s).attr('template');
      slide.elements = [];
      var element = {};
      $(s).find('div').each(function(i,div){
        //to remove all the divs of the sliders, only consider the final boxes
        if($(div).attr("areaid") !== undefined){
          element.id     = $(div).attr('id');
          element.type   = $(div).attr('type');
          element.areaid = $(div).attr('areaid');
          if(element.type==="text"){
            //TODO make this text json safe
            element.body   = $(div).find("div").html();
          } else if(element.type==="image"){
            element.body   = $(div).find('img').attr('src');
            element.style  = $(div).find('img').attr('style');
          } else if(element.type==="iframe"){
            element.body   = $(div).html();
          } else if(element.type==="video"){
						var video = $(div).find("video");
						element.poster = $(video).attr("poster");
						element.style  = $(video).attr('style');

						//Sources
						var sources= '';
						$(video).find('source').each(function(index, source) {
							if(index!=0){
								sources = sources + ',';
							}
							var mymetipe = (typeof $(source).attr("type") != "undefined")?' "mimetype": "' + $(source).attr("type") + '", ':''
              sources = sources + '{' + mymetipe + '"src": "' + $(source).attr("src") + '"}'
            });
						sources = '[' + sources + ']'
						element.sources = sources;
					}
          slide.elements.push(element);
          element = {};
        }
      });
      excursion.slides.push(slide);
      slide = {};
    });
    var jsonexcursion = JSON.stringify(excursion);
    console.log(jsonexcursion);

    $('article').remove();
    $('#menubar').remove();
    $('.theslider').remove();
    $(".nicEdit-panelContain").remove();
    V.SlideManager.init(excursion);

    /*
    //POST to http://server/excursions/
    var params = {
      "excursion[json]": jsonexcursion,
      "authenticity_token" : initOptions["token"]
    }

    $.post(initOptions["postPath"], params, function(data) {
          document.open();
      document.write(data);
      document.close();
      });
      */

  };

	/**
	 * Function to move the slides left one item
	 * curSlide is set by slides.js and it is between 0 and the number of slides, so we use it to move one to the left
	 */
	var _onArrowLeftClicked = function(){
		V.Editor.SlidesUtilities.goToSlide(curSlide);
	};

	/**
	 * Function to move the slides right one item
	 * curSlide is set by slides.js and it is between 0 and the number of slides, so we use +2 to move one to the right
	 */
	var _onArrowRightClicked = function(){
		V.Editor.SlidesUtilities.goToSlide(curSlide+2);
	};

	//////////////////
  ///    Getters
  //////////////////

	var getParams = function(){
		return params;
	}

	var getTemplate = function() {
		if(params['current_el']){
			return params['current_el'].parent().attr('template');
		}
		return null;
	}

	var getCurrentArea = function() {
	    if(params['current_el']){
	      return params['current_el']
	    }
	    return null;
  }

	return {
		init					          : init,
		loadTab 				        : loadTab,
		getValueFromFancybox    : getValueFromFancybox,
		getId                   : getId,
		getTemplate             : getTemplate,
		getCurrentArea          : getCurrentArea,
		getParams               : getParams
	};

}) (VISH, jQuery);
<commit_msg>800x600 fancybox<commit_after>VISH.Editor = (function(V,$,undefined){

	var initOptions;
	var domId = 0;  //number for next doom element id

	// Hash to store:
	// current_el that will be the zone of the template that the user has clicked
	var params = {
		current_el : null
	};

	/**
	 * Initializes the VISH editor
	 * Adds the listeners to the click events in the different images and buttons
	 * Call submodule initializers
	 */
	var init = function(options){
		initOptions = options;

		$("a#addslide").fancybox({
			'width': 800,
    		'height': 600});
		$(document).on('click','.templatethumb', _onTemplateThumbClicked);
		$(document).on('click','#save', _onSaveButtonClicked);
		$(document).on('click','.editable', _onEditableClicked);
		$(document).on('click','.edit_pencil', _onEditableClicked);

		//arrows in button panel
		$(document).on('click','#arrow_left_div', _onArrowLeftClicked);
		$(document).on('click','#arrow_right_div', _onArrowRightClicked);

		var evt = document.createEvent("Event");
		evt.initEvent("OURDOMContentLoaded", false, true); // event type,bubbling,cancelable
		document.dispatchEvent(evt);

		//Init submodules
		V.Debugging.init(true);
		V.Editor.Text.init();
		V.Editor.Video.init();
	};

  ////////////////
  /// Helpers
  ////////////////

  /**
   * Return a unic id.
   */
  var getId = function(){
    domId = domId +1;
    return "unicID_" + domId;
  }

  /**
   * function to dinamically add a css
   */
  var _loadCSS = function(path){
    $("head").append("<link>");
    css = $("head").children(":last");
    css.attr({
      rel:  "stylesheet",
      type: "text/css",
      href: path
    });
  };

  /////////////////////////
  /// Fancy Box Functions
  /////////////////////////

	/**
	 * function to load a tab and its content in the fancybox
	 */
	var loadTab = function (tab_id){
	    //deselect all of them
	    $(".fancy_tab").removeClass("fancy_selected");
	    //select the correct one
	    $("#" + tab_id).addClass("fancy_selected");

	    //hide previous tab
	    $(".fancy_tab_content").hide();
	    //show content
	    $("#" + tab_id + "_content").show();

      //Submodule callbacks
			switch(tab_id)	{
				//Image
        case "tab_pic_from_url":
          V.Editor.Image.onLoadTab("url");
          break;
        case "tab_pic_upload":
          V.Editor.Image.onLoadTab("upload");
          break;
        case "tab_pic_repo":
          V.Editor.Image.Repository.onLoadTab();
          break;
        case "tab_pic_flikr":
          V.Editor.Image.Flikr.onLoadTab();
        break;

				//Video
				case "tab_video_from_url":
				  VISH.Editor.Video.HTML5.onLoadTab("url");
				  break;
				case "tab_video_upload":
          VISH.Editor.Video.HTML5.onLoadTab("upload");
          break;
				case "tab_video_repo":
				  VISH.Editor.Video.Repository.onLoadTab();
				  break;
				case "tab_video_youtube":
				  VISH.Editor.Video.Youtube.onLoadTab();
				break;

				default:
				  break;
			}
	};

  /**
   * Function to get the value from the input identified by the id param and draw it in the zone in params['current_el']
   */
  var getValueFromFancybox = function(id_to_get){
    $.fancybox.close();

		//Call the draw function of the submodule
    switch(id_to_get)  {
      case "picture_url":
        V.Editor.Image.drawImage($("#"+id_to_get).val());
        break;
      case "flash_embed_code":
        console.log("Feature not implemented: Flash embed code")
        break;
      case "video_url":
        V.Editor.Video.HTML5.drawVideoWithUrl($("#"+id_to_get).val())
        break;
      //case "add_your_input_id_here":
        //VISH.Editor.Resource.Module.function($("#"+id_to_get).val())
      // break;
      default:
        break;
    }

    //delete the value
    $("#"+id_to_get).val("");
  };

  /**
   * Removes the lightbox
   */
  var _closeFancybox = function(){
    $.fancybox.close();
  };

  //////////////////
  ///    Events
  //////////////////

	/**
	 * function called when user clicks on template
	 * Includes a new slide following the template selected
	 */
	var _onTemplateThumbClicked = function(event){
		var slide = V.Dummies.getDummy($(this).attr('template'));

		V.Editor.SlidesUtilities.addSlide(slide);
		V.Editor.SlidesUtilities.addThumbnail();

		$.fancybox.close();

		var evt = document.createEvent("Event");
		evt.initEvent("OURDOMContentLoaded", false, true); // event type,bubbling,cancelable
		document.dispatchEvent(evt);
		setTimeout("VISH.Editor.SlidesUtilities.lastSlide()", 300);
	};

	/**
	 * function called when user clicks on an editable element
	 * Event launched when an editable element belonging to the slide is clicked
	 */
	var _onEditableClicked = function(event){
		//first remove the "editable" class because we are going to add clickable icons there and we don´t want it to be editable any more
		$(this).removeClass("editable");
		params['current_el'] = $(this);

		//need to clone it, because we need to show it many times, not only the first one
		//so we need to remove its id
		var content = null;

		if($(this).attr("areaid")==="header"){
			content = $("#menuselect_for_header").clone().attr('id','');
		}
		else{
			content = $("#menuselect").clone().attr('id','');
		}

		//add zone attr to the a elements to remember where to add the content
		content.find("a").each(function(index, domElem) {
			$(domElem).attr("zone", params['current_el'].attr("id"));
		});

		$(this).html(content);

		$("a.addpicture").fancybox({
			'autoDimensions' : false,
			'width': 800,
    		'height': 600,
			'padding' : 0,
			"onStart"  : function(data) {
				//re-set the params['current_el'] to the clicked zone, because maybe the user have clicked in another editable zone before this one
				var clickedZoneId = $(data).attr("zone");
				params['current_el'] = $("#" + clickedZoneId);
				loadTab('tab_pic_from_url');
			}
		});
		$("a.addflash").fancybox({
			'autoDimensions' : false,
			'width': 800,
    		'height': 600,
			'padding' : 0,
			"onStart"  : function(data) {
				var clickedZoneId = $(data).attr("zone");
				params['current_el'] = $("#" + clickedZoneId);
				loadTab('tab_flash_from_url');
			}
		});
		$("a.addvideo").fancybox({
			'autoDimensions' : false,
			'width': 800,
    		'height': 600,
			'padding' : 0,
			"onStart"  : function(data) {
				var clickedZoneId = $(data).attr("zone");
				params['current_el'] = $("#" + clickedZoneId);
				loadTab('tab_video_from_url');
			}
		});
	};

  /**
   * function called when user clicks on save
   * Generates the json for the current slides
   * covers the section element and every article inside
   * finally calls SlideManager with the generated json
   */
  var _onSaveButtonClicked = function(){
    var excursion = {};
    //TODO decide this params
    excursion.id = '';
    excursion.title = '';
    excursion.description = '';
    excursion.author = '';
    excursion.slides = [];
    var slide = {};
    $('article').each(function(index,s){
      slide.id = $(s).attr('id'); //TODO what if saved before!
      slide.template = $(s).attr('template');
      slide.elements = [];
      var element = {};
      $(s).find('div').each(function(i,div){
        //to remove all the divs of the sliders, only consider the final boxes
        if($(div).attr("areaid") !== undefined){
          element.id     = $(div).attr('id');
          element.type   = $(div).attr('type');
          element.areaid = $(div).attr('areaid');
          if(element.type==="text"){
            //TODO make this text json safe
            element.body   = $(div).find("div").html();
          } else if(element.type==="image"){
            element.body   = $(div).find('img').attr('src');
            element.style  = $(div).find('img').attr('style');
          } else if(element.type==="iframe"){
            element.body   = $(div).html();
          } else if(element.type==="video"){
						var video = $(div).find("video");
						element.poster = $(video).attr("poster");
						element.style  = $(video).attr('style');

						//Sources
						var sources= '';
						$(video).find('source').each(function(index, source) {
							if(index!=0){
								sources = sources + ',';
							}
							var mymetipe = (typeof $(source).attr("type") != "undefined")?' "mimetype": "' + $(source).attr("type") + '", ':''
              sources = sources + '{' + mymetipe + '"src": "' + $(source).attr("src") + '"}'
            });
						sources = '[' + sources + ']'
						element.sources = sources;
					}
          slide.elements.push(element);
          element = {};
        }
      });
      excursion.slides.push(slide);
      slide = {};
    });
    var jsonexcursion = JSON.stringify(excursion);
    console.log(jsonexcursion);

    $('article').remove();
    $('#menubar').remove();
    $('.theslider').remove();
    $(".nicEdit-panelContain").remove();
    V.SlideManager.init(excursion);

    /*
    //POST to http://server/excursions/
    var params = {
      "excursion[json]": jsonexcursion,
      "authenticity_token" : initOptions["token"]
    }

    $.post(initOptions["postPath"], params, function(data) {
          document.open();
      document.write(data);
      document.close();
      });
      */

  };

	/**
	 * Function to move the slides left one item
	 * curSlide is set by slides.js and it is between 0 and the number of slides, so we use it to move one to the left
	 */
	var _onArrowLeftClicked = function(){
		V.Editor.SlidesUtilities.goToSlide(curSlide);
	};

	/**
	 * Function to move the slides right one item
	 * curSlide is set by slides.js and it is between 0 and the number of slides, so we use +2 to move one to the right
	 */
	var _onArrowRightClicked = function(){
		V.Editor.SlidesUtilities.goToSlide(curSlide+2);
	};

	//////////////////
  ///    Getters
  //////////////////

	var getParams = function(){
		return params;
	}

	var getTemplate = function() {
		if(params['current_el']){
			return params['current_el'].parent().attr('template');
		}
		return null;
	}

	var getCurrentArea = function() {
	    if(params['current_el']){
	      return params['current_el']
	    }
	    return null;
  }

	return {
		init					          : init,
		loadTab 				        : loadTab,
		getValueFromFancybox    : getValueFromFancybox,
		getId                   : getId,
		getTemplate             : getTemplate,
		getCurrentArea          : getCurrentArea,
		getParams               : getParams
	};

}) (VISH, jQuery);
<|endoftext|>


<commit_before>import { ALL_DOMAINS } from '../actions/overview'
import isDefined from '../../../utils/isDefined'
import * as selectOverviewValue from '../selectors/selectOverviewValue'

export default (state) => {

	const fetching = (
		selectOverviewValue.withoutType(state, ALL_DOMAINS).fetching === true ||
		Object.values(state.overview.value).some((value) => value.fetching) === true ||
		state.views.fetching === true ||
		state.pages.fetching === true ||
		state.referrers.fetching === true ||
		state.durations.fetching === true ||
		state.systems.fetching === true ||
		state.devices.fetching === true ||
		state.browsers.fetching === true ||
		state.sizes.fetching === true ||
		state.languages.fetching === true ||
		state.domains.fetching === true ||
		state.token.fetching === true
	)

	const errors = [
		selectOverviewValue.withoutType(state, ALL_DOMAINS).error,
		...Object.values(state.overview.value).map((value) => value.error),
		state.views.error,
		state.pages.error,
		state.referrers.error,
		state.durations.error,
		state.systems.error,
		state.devices.error,
		state.browsers.error,
		state.sizes.error,
		state.languages.error,
		state.domains.error,
		state.token.error
	].filter(isDefined)

	return Object.assign({}, state, {
		fetching,
		errors
	})

}<commit_msg>Include fetching and error states in global fetching and errors variable<commit_after>import { ALL_DOMAINS } from '../actions/overview'
import isDefined from '../../../utils/isDefined'
import * as selectOverviewValue from '../selectors/selectOverviewValue'

export default (state) => {

	const fetching = (
		selectOverviewValue.withoutType(state, ALL_DOMAINS).fetching === true ||
		Object.values(state.overview.value).some((value) => value.fetching) === true ||
		state.views.fetching === true ||
		state.pages.fetching === true ||
		state.referrers.fetching === true ||
		state.durations.fetching === true ||
		state.systems.fetching === true ||
		state.devices.fetching === true ||
		state.browsers.fetching === true ||
		state.sizes.fetching === true ||
		state.languages.fetching === true ||
		state.domains.fetching === true ||
		state.token.fetching === true ||
		state.permanentTokens.fetching === true
	)

	const errors = [
		selectOverviewValue.withoutType(state, ALL_DOMAINS).error,
		...Object.values(state.overview.value).map((value) => value.error),
		state.views.error,
		state.pages.error,
		state.referrers.error,
		state.durations.error,
		state.systems.error,
		state.devices.error,
		state.browsers.error,
		state.sizes.error,
		state.languages.error,
		state.domains.error,
		state.token.error,
		state.permanentTokens.error
	].filter(isDefined)

	return Object.assign({}, state, {
		fetching,
		errors
	})

}<|endoftext|>


<commit_before>// generated on 2015-07-08 using generator-gulp-webapp 1.0.1
import gulp from 'gulp';
import gulpLoadPlugins from 'gulp-load-plugins';
import browserSync from 'browser-sync';
import del from 'del';
import {stream as wiredep} from 'wiredep';

const $ = gulpLoadPlugins();
const reload = browserSync.reload;

gulp.task('styles', () => {
  return gulp.src('app/styles/*.scss')
    .pipe($.plumber())
    .pipe($.sourcemaps.init())
    .pipe($.sass.sync({
      outputStyle: 'expanded',
      precision: 10,
      includePaths: ['.']
    }).on('error', $.sass.logError))
    .pipe($.autoprefixer({browsers: ['last 1 version']}))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('.tmp/styles'))
    .pipe(reload({stream: true}));
});

function lint(files, options) {
  return () => {
    return gulp.src(files)
      .pipe(reload({stream: true, once: true}))
      .pipe($.eslint(options))
      .pipe($.eslint.format())
      .pipe($.if(!browserSync.active, $.eslint.failAfterError()));
  };
}
const testLintOptions = {
  env: {
    mocha: true
  },
  globals: {
    assert: false,
    expect: false,
    should: false
  }
};

gulp.task('lint', lint('app/scripts/**/*.js'));
gulp.task('lint:test', lint('test/spec/**/*.js', testLintOptions));

gulp.task('html', ['styles'], () => {
  const assets = $.useref.assets({searchPath: ['.tmp', 'app', '.']});

  return gulp.src('app/*.html')
    .pipe(assets)
    .pipe($.if('*.js', $.uglify()))
    .pipe($.if('*.css', $.minifyCss({compatibility: '*'})))
    .pipe(assets.restore())
    .pipe($.useref())
    .pipe($.if('*.html', $.minifyHtml({conditionals: true, loose: true})))
    .pipe(gulp.dest('dist'));
});

gulp.task('images', () => {
  return gulp.src('app/images/**/*')
    .pipe($.if($.if.isFile, $.cache($.imagemin({
      progressive: true,
      interlaced: true,
      // don't remove IDs from SVGs, they are often used
      // as hooks for embedding and styling
      svgoPlugins: [{cleanupIDs: false}]
    }))
    .on('error', function (err) {
      console.log(err);
      this.end();
    })))
    .pipe(gulp.dest('dist/images'));
});

gulp.task('fonts', () => {
  return gulp.src(require('main-bower-files')({
    filter: '**/*.{eot,svg,ttf,woff,woff2}'
  }).concat('app/fonts/**/*'))
    .pipe(gulp.dest('.tmp/fonts'))
    .pipe(gulp.dest('dist/fonts'));
});

gulp.task('extras', () => {
  return gulp.src([
    'app/*.*',
    '!app/*.html'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'));
});

gulp.task('clean', del.bind(null, ['.tmp', 'dist']));

gulp.task('serve', ['styles', 'fonts'], () => {
  browserSync({
    notify: false,
    port: 9000,
    server: {
      baseDir: ['.tmp', 'app'],
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  gulp.watch([
    'app/*.html',
    'app/scripts/**/*.js',
    'app/images/**/*',
    '.tmp/fonts/**/*'
  ]).on('change', reload);

  gulp.watch('app/styles/**/*.scss', ['styles']);
  gulp.watch('app/fonts/**/*', ['fonts']);
  gulp.watch('bower.json', ['wiredep', 'fonts']);
});

gulp.task('serve:dist', () => {
  browserSync({
    notify: false,
    port: 9000,
    server: {
      baseDir: ['dist']
    }
  });
});

gulp.task('serve:test', () => {
  browserSync({
    notify: false,
    port: 9000,
    ui: false,
    server: {
      baseDir: 'test',
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  gulp.watch('test/spec/**/*.js').on('change', reload);
  gulp.watch('test/spec/**/*.js', ['lint:test']);
});

// inject bower components
gulp.task('wiredep', () => {
  gulp.src('app/styles/*.scss')
    .pipe(wiredep({
      ignorePath: /^(\.\.\/)+/
    }))
    .pipe(gulp.dest('app/styles'));

  gulp.src('app/*.html')
    .pipe(wiredep({
      exclude: ['bootstrap-sass'],
      ignorePath: /^(\.\.\/)*\.\./
    }))
    .pipe(gulp.dest('app'));
});

gulp.task('build', ['lint', 'html', 'images', 'fonts', 'extras'], () => {
  return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
});

gulp.task('default', ['clean'], () => {
  gulp.start('build');
});
<commit_msg>updated gulpfile to open in directory<commit_after>// generated on 2015-07-08 using generator-gulp-webapp 1.0.1
import gulp from 'gulp';
import gulpLoadPlugins from 'gulp-load-plugins';
import browserSync from 'browser-sync';
import del from 'del';
import {stream as wiredep} from 'wiredep';

const $ = gulpLoadPlugins();
const reload = browserSync.reload;

gulp.task('styles', () => {
  return gulp.src('app/styles/*.scss')
    .pipe($.plumber())
    .pipe($.sourcemaps.init())
    .pipe($.sass.sync({
      outputStyle: 'expanded',
      precision: 10,
      includePaths: ['.']
    }).on('error', $.sass.logError))
    .pipe($.autoprefixer({browsers: ['last 1 version']}))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest('.tmp/styles'))
    .pipe(reload({stream: true}));
});

function lint(files, options) {
  return () => {
    return gulp.src(files)
      .pipe(reload({stream: true, once: true}))
      .pipe($.eslint(options))
      .pipe($.eslint.format())
      .pipe($.if(!browserSync.active, $.eslint.failAfterError()));
  };
}
const testLintOptions = {
  env: {
    mocha: true
  },
  globals: {
    assert: false,
    expect: false,
    should: false
  }
};

gulp.task('lint', lint('app/scripts/**/*.js'));
gulp.task('lint:test', lint('test/spec/**/*.js', testLintOptions));

gulp.task('html', ['styles'], () => {
  const assets = $.useref.assets({searchPath: ['.tmp', 'app', '.']});

  return gulp.src('app/*.html')
    .pipe(assets)
    .pipe($.if('*.js', $.uglify()))
    .pipe($.if('*.css', $.minifyCss({compatibility: '*'})))
    .pipe(assets.restore())
    .pipe($.useref())
    .pipe($.if('*.html', $.minifyHtml({conditionals: true, loose: true})))
    .pipe(gulp.dest('dist'));
});

gulp.task('images', () => {
  return gulp.src('app/images/**/*')
    .pipe($.if($.if.isFile, $.cache($.imagemin({
      progressive: true,
      interlaced: true,
      // don't remove IDs from SVGs, they are often used
      // as hooks for embedding and styling
      svgoPlugins: [{cleanupIDs: false}]
    }))
    .on('error', function (err) {
      console.log(err);
      this.end();
    })))
    .pipe(gulp.dest('dist/images'));
});

gulp.task('fonts', () => {
  return gulp.src(require('main-bower-files')({
    filter: '**/*.{eot,svg,ttf,woff,woff2}'
  }).concat('app/fonts/**/*'))
    .pipe(gulp.dest('.tmp/fonts'))
    .pipe(gulp.dest('dist/fonts'));
});

gulp.task('extras', () => {
  return gulp.src([
    'app/*.*',
    '!app/*.html'
  ], {
    dot: true
  }).pipe(gulp.dest('dist'));
});

gulp.task('clean', del.bind(null, ['.tmp', 'dist']));

gulp.task('serve', ['styles', 'fonts'], () => {
  browserSync({
    notify: false,
    port: 9000,
    server: {
      baseDir: ['app', '.tmp'],
      routes: {
        '/bower_components': 'bower_components'
      }
      directory: true
    }
  });

  gulp.watch([
    'app/*.html',
    'app/scripts/**/*.js',
    'app/images/**/*',
    '.tmp/fonts/**/*'
  ]).on('change', reload);

  gulp.watch('app/styles/**/*.scss', ['styles']);
  gulp.watch('app/fonts/**/*', ['fonts']);
  gulp.watch('bower.json', ['wiredep', 'fonts']);
});

gulp.task('serve:dist', () => {
  browserSync({
    notify: false,
    port: 9000,
    server: {
      baseDir: ['dist']
    }
  });
});

gulp.task('serve:test', () => {
  browserSync({
    notify: false,
    port: 9000,
    ui: false,
    server: {
      baseDir: 'test',
      routes: {
        '/bower_components': 'bower_components'
      }
    }
  });

  gulp.watch('test/spec/**/*.js').on('change', reload);
  gulp.watch('test/spec/**/*.js', ['lint:test']);
});

// inject bower components
gulp.task('wiredep', () => {
  gulp.src('app/styles/*.scss')
    .pipe(wiredep({
      ignorePath: /^(\.\.\/)+/
    }))
    .pipe(gulp.dest('app/styles'));

  gulp.src('app/*.html')
    .pipe(wiredep({
      exclude: ['bootstrap-sass'],
      ignorePath: /^(\.\.\/)*\.\./
    }))
    .pipe(gulp.dest('app'));
});

gulp.task('build', ['lint', 'html', 'images', 'fonts', 'extras'], () => {
  return gulp.src('dist/**/*').pipe($.size({title: 'build', gzip: true}));
});

gulp.task('default', ['clean'], () => {
  gulp.start('build');
});
<|endoftext|>


<commit_before>'use strict';
/**
 * @ngInject
 */
var ExpeditionSearchController = function ($scope, $location, $controller, Expedition, npdcAppConfig) {

  $controller('NpolarBaseController', { $scope: $scope });
  $scope.resource = Expedition;

  npdcAppConfig.search.local.results.detail = (e) => {
    return "Activity start: " + e.activity[0].departed.split('T')[0];
   };

  npdcAppConfig.cardTitle = "Expedition Archive";
  npdcAppConfig.search.local.results.subtitle = "type";
  npdcAppConfig.search.local.filterUi = {
    'year-activity.departed': {
      type: 'range'
    },
    'updated': {
      type: 'hidden'
    }
  };

  let query = function() {
    let defaults = { limit: "all", sort: "-updated", fields: 'code,id,updated,type,activity.departed',
      'date-year': 'activity.departed', facets: 'tags,people.email,updated,locations.area' };
    let invariants = $scope.security.isAuthenticated() ? {} : {} ;
    return Object.assign({}, defaults, $location.search(), invariants);
  };

  $scope.search(query());

  $scope.$on('$locationChangeSuccess', (event, data) => {
    $scope.search(query());
  });

};

module.exports = ExpeditionSearchController;
<commit_msg>BaseController handles location.search<commit_after>'use strict';
/**
 * @ngInject
 */
var ExpeditionSearchController = function ($scope, $location, $controller, Expedition, npdcAppConfig) {

  $controller('NpolarBaseController', { $scope: $scope });
  $scope.resource = Expedition;

  npdcAppConfig.search.local.results.detail = (e) => {
    return "Activity start: " + e.activity[0].departed.split('T')[0];
   };

  npdcAppConfig.cardTitle = "Expedition Archive";
  npdcAppConfig.search.local.results.subtitle = "type";
  npdcAppConfig.search.local.filterUi = {
    'year-activity.departed': {
      type: 'range'
    },
    'updated': {
      type: 'hidden'
    }
  };

  let query = function() {
    let defaults = { limit: "all", sort: "-updated", fields: 'code,id,updated,type,activity.departed',
      'date-year': 'activity.departed', facets: 'tags,people.email,updated,locations.area' };
    let invariants = $scope.security.isAuthenticated() ? {} : {} ;
    return Object.assign({}, defaults, invariants);
  };

  $scope.search(query());

  $scope.$on('$locationChangeSuccess', (event, data) => {
    $scope.search(query());
  });

};

module.exports = ExpeditionSearchController;
<|endoftext|>