<commit_before>var renderer, scene, camera;

var pointcloud;
var raycaster, intersects;
var mouse = new THREE.Vector2();
var intersection = null;
var spheres = [];
var spheresIndex = 0;
var clock;

var threshold = 0.1;
var pointSize = 0.05;
var width = 150;
var length = 150;
var rotateY = new THREE.Matrix4().makeRotationY( 0.005 );

init();
animate();

function generatePointCloudGeometry( color, width, length ) {

    var geometry = new THREE.BufferGeometry();
    var numPoints = width*length;

    var positions = new Float32Array( numPoints*3 );
    var colors = new Float32Array( numPoints*3 );

    var k = 0;

    for( var i = 0; i < width; i++ ) {

        for( var j = 0; j < length; j++ ) {

            var u = i / width;
            var v = j / length;
            var x = u - 0.5;
            var y = ( Math.cos( u * Math.PI * 8 ) + Math.sin( v * Math.PI * 8 ) ) / 20;
            var z = v - 0.5;

            positions[ 3 * k ] = x;
            positions[ 3 * k + 1 ] = y;
            positions[ 3 * k + 2 ] = z;

            var intensity = ( y + 0.1 ) * 5;
            colors[ 3 * k ] = color.r * intensity;
            colors[ 3 * k + 1 ] = color.g * intensity;
            colors[ 3 * k + 2 ] = color.b * intensity;

            k++;

        }

    }

    geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
    geometry.computeBoundingBox();

    return geometry;

}

function generatePointcloud( color, width, length ) {

    var geometry = generatePointCloudGeometry( color, width, length );

    var material = new THREE.PointCloudMaterial( { size: pointSize, vertexColors: THREE.VertexColors } );
    var pointcloud = new THREE.PointCloud( geometry, material );

    return pointcloud;

}

function generateRegularPointcloud( color, width, length ) {

    var geometry = new THREE.Geometry();
    var numPoints = width * length;

    var colors = [];

    var k = 0;

    for( var i = 0; i < width; i++ ) {

        for( var j = 0; j < length; j++ ) {

            var u = i / width;
            var v = j / length;
            var x = u - 0.5;
            var y = ( Math.cos( u * Math.PI * 8 ) + Math.sin( v * Math.PI * 8 ) ) / 20;
            var z = v - 0.5;
            var v = new THREE.Vector3( x, y, z );

            var intensity = ( y + 0.1 ) * 7;
            colors[ 3 * k ] = color.r * intensity;
            colors[ 3 * k + 1 ] = color.g * intensity;
            colors[ 3 * k + 2 ] = color.b * intensity;

            geometry.vertices.push( v );
            colors[ k ] = ( color.clone().multiplyScalar( intensity ) );

            k++;

        }

    }

    geometry.colors = colors;
    geometry.computeBoundingBox();

    var material = new THREE.PointCloudMaterial( { size: pointSize, vertexColor: THREE.VertexColors } );
    var pointcloud = new THREE.PointCloud( geometry, material );

    return pointcloud;

}

function onWindowResize() {

    renderer.setSize( window.innerWidth, window.innerHeight );
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

}

function onDocumentMouseMove( event ) {

    event.preventDefault();

    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

}

function init() {

    container = document.getElementById( 'container' );

    scene = new THREE.Scene();

    clock = new THREE.Clock();

    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 0, 20 ) );
    camera.applyMatrix( new THREE.Matrix4().makeRotationX( -0.5 ) );

    //

    pointcloud = generatePointcloud( new THREE.Color( 0, 1, 0 ), width, length );
    pointcloud.scale.set( 10, 10, 10 );
    scene.add( pointcloud );

    //

    var sphereGeometry = new THREE.SphereGeometry( 0.1, 32, 32 );
    var sphereMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, shading: THREE.FlatShading } );

    for( var i = 0; i < 40; i++ ) {

        var sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
        scene.add( sphere );
        spheres.push( sphere );

    }

    //

    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    container.appendChild( renderer.domElement );

    //

    raycaster = new THREE.Raycaster();
    raycaster.params.PointCloud.threshold = threshold;

    //

    window.addEventListener( 'resize', onWindowResize, false );
    document.addEventListener( 'mousemove', onDocumentMouseMove, false );

}

function animate() {

    requestAnimationFrame( animate );

    render();

}

var toggle = 0;

function render() {

    camera.applyMatrix( rotateY );
    camera.updateMatrixWorld();

    raycaster.setFromCamera( mouse, camera );

    var intersections = raycaster.intersectObject( pointcloud );
    intersection = ( intersections.length ) > 0 ? intersections[ 0 ] : null;

    if( toggle > 0.02 && intersection != null ) {

        spheres[ spheresIndex ].position.copy( intersection.point );
        spheres[ spheresIndex ].scale.set( 1, 1, 1 );
        spheresIndex = ( spheresIndex + 1 ) % spheres.length;

        toggle = 0;

    }

    for( var i = 0; i < spheres.length; i++ ) {

        var sphere = spheres[ i ];
        sphere.scale.multiplyScalar( 0.98 );
        sphere.scale.clampScalar( 0.01, 1 );

    }

    toggle += clock.getDelta();

    renderer.render( scene, camera );

}
<commit_msg>Removing raycaster for now. Focusing on developing pointcloud.<commit_after>var renderer, scene, camera;

var pointcloud;

var mouse = new THREE.Vector2();
var intersection = null;

var clock;

var threshold = 0.1;
var pointSize = 0.05;
var width = 150;
var length = 150;
var rotateY = new THREE.Matrix4().makeRotationY( 0.005 );

init();
animate();

function generatePointCloudGeometry( color, width, length ) {

    var geometry = new THREE.BufferGeometry();
    var numPoints = width*length;

    var positions = new Float32Array( numPoints*3 );
    var colors = new Float32Array( numPoints*3 );

    var k = 0;

    for( var i = 0; i < width; i++ ) {

        for( var j = 0; j < length; j++ ) {

            var u = i / width;
            var v = j / length;
            var x = u - 0.5;
            var y = ( Math.cos( u * Math.PI * 8 ) + Math.sin( v * Math.PI * 8 ) ) / 20;
            var z = v - 0.5;

            positions[ 3 * k ] = x;
            positions[ 3 * k + 1 ] = y;
            positions[ 3 * k + 2 ] = z;

            var intensity = ( y + 0.1 ) * 5;
            colors[ 3 * k ] = color.r * intensity;
            colors[ 3 * k + 1 ] = color.g * intensity;
            colors[ 3 * k + 2 ] = color.b * intensity;

            k++;

        }

    }

    geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
    geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
    geometry.computeBoundingBox();

    return geometry;

}

function generatePointcloud( color, width, length ) {

    var geometry = generatePointCloudGeometry( color, width, length );

    var material = new THREE.PointCloudMaterial( { size: pointSize, vertexColors: THREE.VertexColors } );
    var pointcloud = new THREE.PointCloud( geometry, material );

    return pointcloud;

}

function generateRegularPointcloud( color, width, length ) {

    var geometry = new THREE.Geometry();
    var numPoints = width * length;

    var colors = [];

    var k = 0;

    for( var i = 0; i < width; i++ ) {

        for( var j = 0; j < length; j++ ) {

            var u = i / width;
            var v = j / length;
            var x = u - 0.5;
            var y = ( Math.cos( u * Math.PI * 8 ) + Math.sin( v * Math.PI * 8 ) ) / 20;
            var z = v - 0.5;
            var v = new THREE.Vector3( x, y, z );

            var intensity = ( y + 0.1 ) * 7;
            colors[ 3 * k ] = color.r * intensity;
            colors[ 3 * k + 1 ] = color.g * intensity;
            colors[ 3 * k + 2 ] = color.b * intensity;

            geometry.vertices.push( v );
            colors[ k ] = ( color.clone().multiplyScalar( intensity ) );

            k++;

        }

    }

    geometry.colors = colors;
    geometry.computeBoundingBox();

    var material = new THREE.PointCloudMaterial( { size: pointSize, vertexColor: THREE.VertexColors } );
    var pointcloud = new THREE.PointCloud( geometry, material );

    return pointcloud;

}

function onWindowResize() {

    renderer.setSize( window.innerWidth, window.innerHeight );
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

}

function onDocumentMouseMove( event ) {

    event.preventDefault();

    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

}

function init() {

    container = document.getElementById( 'container' );

    scene = new THREE.Scene();

    clock = new THREE.Clock();

    camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.applyMatrix( new THREE.Matrix4().makeTranslation( 0, 0, 20 ) );
    camera.applyMatrix( new THREE.Matrix4().makeRotationX( -0.5 ) );

    //

    pointcloud = generatePointcloud( new THREE.Color( 0, 1, 0 ), width, length );
    pointcloud.scale.set( 10, 10, 10 );
    scene.add( pointcloud );

    //

    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    container.appendChild( renderer.domElement );

    //

    window.addEventListener( 'resize', onWindowResize, false );
    document.addEventListener( 'mousemove', onDocumentMouseMove, false );

}

function animate() {

    requestAnimationFrame( animate );

    render();

}

function render() {

    camera.applyMatrix( rotateY );
    camera.updateMatrixWorld();

    renderer.render( scene, camera );

}
<|endoftext|>


<commit_before>'use strict';

angular.module('polls').controller('PollsSearchController', [
  '$location',
  '$rootScope',
  '$scope',
  '$state',
  'Authentication',
  'CategorysService',
  'Action',
  '$stateParams',
  'Storages',
  'Constants',
  'toastr',
  'ngDialog',
  'Profile',
  function ($location, $rootScope, $scope, $state, Authentication, Categorys, Action, $stateParams, Storages, Constants, toast, dialog, Profile) {
    $scope.user = Authentication.user;
    $scope.isLogged = ($scope.user) ? true : false;
    $scope.detailToggle = -1;
    $scope.form = {};
    $scope.categorys = Categorys.query();

    $scope.condition = {};
    $scope.busy = false;
    $scope.polls = [];

    initCondition();
    function initCondition() {
      var param = $location.search();
      if (_.isEmpty(param)) {
        $scope.condition = JSON.parse(Storages.get_local(Constants.storages.public_search_condition, JSON.stringify({})));
        if ($scope.condition.by) {
          Profile.get({ userId: $scope.condition.by }, _user => {
            $scope.selectedUser = _user;
          });
        }
      } else {
        _.extend($scope.condition, param);
      }
      if (!_.isEmpty(param)) {
        search();
      }
    }

    $scope.search = search;
    function search() {
      if ($scope.busy === true) return;
      $scope.busy = true;
      Action.search($scope.condition)
        .then(res => {
          // $scope.polls = res.data;
          console.log(res.data);
          // buildPager();
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
          $scope.busy = false;
        });
      Storages.set_local(Constants.storages.public_search_condition, JSON.stringify($scope.condition));
    };
    $scope.buildPager = buildPager;
    function buildPager() {
      $scope.pagedItems = [];
      $scope.itemsPerPage = 10;
      figureOutItemsToDisplay();
      $scope.busy = false;
    }

    $scope.clear_filter = () => {
      $scope.condition = {};
      $scope.selectedUser = undefined;
      $scope.$broadcast('angucomplete-alt:clearInput');
    };
    $scope.clear_created_start = () => {
      delete $scope.condition.created_start;
    };
    $scope.clear_created_end = () => {
      delete $scope.condition.created_end;
    };
    $scope.selectedUserFn = function (selected) {
      if (selected) {
        $scope.condition.by = selected.originalObject._id;
        $scope.selectedUser = selected.originalObject;
      } else {
        delete $scope.condition.by;
        $scope.selectedUser = undefined;
      }
    };

    $scope.delete_poll = (poll) => {
      if (poll.user._id !== $scope.user._id) {
        toast.error('You are not authorized.', 'Error!');
        return;
      }
      $scope.message_title = 'Delete poll!';
      $scope.message_content = 'Are you sure you want to delete this poll?';
      $scope.dialog_type = 3;
      $scope.buton_label = 'delete';
      dialog.openConfirm({
        scope: $scope,
        templateUrl: 'modules/core/client/views/templates/confirm.dialog.template.html'
      }).then(confirm => {
        handle_delete();
      }, reject => {
      });
      function handle_delete() {
        $scope.polls = _.reject($scope.polls, function (item) {
          return item.poll._id === poll._id;
        });
        // Action.delete_poll(poll);
      }
    };
    $scope.report_poll = (poll) => {
      if (poll.reported) {
        toast.error('You are already reported ' + poll.title, 'Error!');
        return;
      }
      dialog.openConfirm({
        scope: $scope,
        templateUrl: 'modules/core/client/views/templates/report.dialog.template.html'
      }).then(reason => {
        handle_confirm(reason);
      }, reject => {
      });
      function handle_confirm(reason) {
        Action.save_report(poll, reason)
          .then(res => {
            poll.reported = (res) ? true : false;
            toast.success('You have successfully reported ' + poll.title, 'Thank you!');
          })
          .catch(err => {
            toast.error(err.message, 'Error!');
          });
      }
    };
    $scope.bookmark_poll = (poll) => {
      if (poll.bookmarked) {
        toast.error('You are already bookmark ' + poll.title, 'Error!');
        return;
      }
      Action.save_bookmark(poll._id)
        .then(res => {
          poll.bookmarked = (res) ? true : false;
          toast.success('Added ' + poll.title + ' to bookmarks.', 'Success!');
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    };
    $scope.follow_poll = (poll) => {
      if (!$scope.isLogged) {
        toast.error('You must login to follow poll.', 'Error!');
        return;
      }
      Action.save_follow(poll.follow)
        .then(res => {
          if (res) {
            poll.follow = res;
            toast.success('You followed ' + poll.title, 'Success!');
          } else {
            poll.follow = { poll: poll._id };
          }
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    };
  }
]);
<commit_msg>Commited from lenh at Mon, Aug 14, 2017  5:23:32 PM<commit_after>'use strict';

angular.module('polls').controller('PollsSearchController', [
  '$location',
  '$rootScope',
  '$scope',
  '$state',
  'Authentication',
  'CategorysService',
  'Action',
  '$stateParams',
  'Storages',
  'Constants',
  'toastr',
  'ngDialog',
  'Profile',
  function ($location, $rootScope, $scope, $state, Authentication, Categorys, Action, $stateParams, Storages, Constants, toast, dialog, Profile) {
    $scope.user = Authentication.user;
    $scope.isLogged = ($scope.user) ? true : false;
    $scope.detailToggle = -1;
    $scope.form = {};
    $scope.categorys = Categorys.query();

    $scope.condition = {};
    $scope.busy = false;
    $scope.polls = [];

    initCondition();
    function initCondition() {
      var param = $location.search();
      if (_.isEmpty(param)) {
        $scope.condition = JSON.parse(Storages.get_local(Constants.storages.public_search_condition, JSON.stringify({})));
        if ($scope.condition.by) {
          Profile.get({ userId: $scope.condition.by }, _user => {
            $scope.selectedUser = _user;
          });
        }
      } else {
        _.extend($scope.condition, param);
      }
      if (!_.isEmpty(param)) {
        search();
      }
    }

    $scope.search = search;
    function search() {
      if ($scope.busy === true) return;
      $scope.busy = true;
      Action.search($scope.condition)
        .then(res => {
          // $scope.polls = res.data;
          console.log(res.data);
          // buildPager();
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
          $scope.busy = false;
        });
      Storages.set_local(Constants.storages.public_search_condition, JSON.stringify($scope.condition));
    }
    $scope.buildPager = buildPager;
    function buildPager() {
      $scope.pagedItems = [];
      $scope.itemsPerPage = 10;
      // figureOutItemsToDisplay();
      $scope.busy = false;
    }

    $scope.clear_filter = () => {
      $scope.condition = {};
      $scope.selectedUser = undefined;
      $scope.$broadcast('angucomplete-alt:clearInput');
    };
    $scope.clear_created_start = () => {
      delete $scope.condition.created_start;
    };
    $scope.clear_created_end = () => {
      delete $scope.condition.created_end;
    };
    $scope.selectedUserFn = function (selected) {
      if (selected) {
        $scope.condition.by = selected.originalObject._id;
        $scope.selectedUser = selected.originalObject;
      } else {
        delete $scope.condition.by;
        $scope.selectedUser = undefined;
      }
    };

    $scope.delete_poll = (poll) => {
      if (poll.user._id !== $scope.user._id) {
        toast.error('You are not authorized.', 'Error!');
        return;
      }
      $scope.message_title = 'Delete poll!';
      $scope.message_content = 'Are you sure you want to delete this poll?';
      $scope.dialog_type = 3;
      $scope.buton_label = 'delete';
      dialog.openConfirm({
        scope: $scope,
        templateUrl: 'modules/core/client/views/templates/confirm.dialog.template.html'
      }).then(confirm => {
        handle_delete();
      }, reject => {
      });
      function handle_delete() {
        $scope.polls = _.reject($scope.polls, function (item) {
          return item.poll._id === poll._id;
        });
        // Action.delete_poll(poll);
      }
    };
    $scope.report_poll = (poll) => {
      if (poll.reported) {
        toast.error('You are already reported ' + poll.title, 'Error!');
        return;
      }
      dialog.openConfirm({
        scope: $scope,
        templateUrl: 'modules/core/client/views/templates/report.dialog.template.html'
      }).then(reason => {
        handle_confirm(reason);
      }, reject => {
      });
      function handle_confirm(reason) {
        Action.save_report(poll, reason)
          .then(res => {
            poll.reported = (res) ? true : false;
            toast.success('You have successfully reported ' + poll.title, 'Thank you!');
          })
          .catch(err => {
            toast.error(err.message, 'Error!');
          });
      }
    };
    $scope.bookmark_poll = (poll) => {
      if (poll.bookmarked) {
        toast.error('You are already bookmark ' + poll.title, 'Error!');
        return;
      }
      Action.save_bookmark(poll._id)
        .then(res => {
          poll.bookmarked = (res) ? true : false;
          toast.success('Added ' + poll.title + ' to bookmarks.', 'Success!');
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    };
    $scope.follow_poll = (poll) => {
      if (!$scope.isLogged) {
        toast.error('You must login to follow poll.', 'Error!');
        return;
      }
      Action.save_follow(poll.follow)
        .then(res => {
          if (res) {
            poll.follow = res;
            toast.success('You followed ' + poll.title, 'Success!');
          } else {
            poll.follow = { poll: poll._id };
          }
        })
        .catch(err => {
          toast.error(err.message, 'Error!');
        });
    };
  }
]);
<|endoftext|>


<commit_before>import React from 'react';
import classNames from 'classnames';
import Row from './../row';

class InlineInputs extends React.Component {
  static propTypes = {
    /**
     * Defines the label text for the heading.
     *
     * @property label
     * @type {String}
     */
    label: React.PropTypes.string
  }

    /**
   * Returns the classes for the component.
   *
   * @method classes
   * @return {String}
   */
  get classes() {
    return classNames(
      "carbon-inline-inputs",
      this.props.className
    );
  }

  render() {
    return (

        { this.props.label }
        <Row gutter="none" className="carbon-inline-inputs-wrapper">
          { this.props.children }
        </Row>

    );
  }
}

export default InlineInputs;
<commit_msg>SI-131: Refactor InlineInputs into functional component<commit_after>import React from 'react';
import classNames from 'classnames';

// Carbon
import Row from './../row';

let InlineInputs = (props) =>

    { props.label }
    <Row gutter="none" className="carbon-inline-inputs-wrapper">
      { props.children }
    </Row>

;

const classes = (props) => {
  return classNames(
    "carbon-inline-inputs",
    props.className
  );
};

InlineInputs.propTypes = {
  /**
   * Defines the label text for the heading.
   *
   * @property label
   * @type {String}
   */
  label: React.PropTypes.string
};

export default InlineInputs;
<|endoftext|>


<commit_before>import Ember from 'ember';
import { moduleForComponent, test } from 'ember-qunit';

moduleForComponent( 'sl-calendar', 'Unit - component: sl-calendar', {
    needs: [
        'component:sl-calendar-day',
        'component:sl-calendar-month',
        'component:sl-calendar-year',
        'template:components/sl-calendar-day',
        'template:components/sl-calendar-month',
        'template:components/sl-calendar-year'
    ]
});

test( 'Default class name is present', function( assert ) {
    var $component = this.render();

    assert.ok(
        $component.hasClass( 'sl-calendar' ),
        'Default rendered component has class "sl-calendar"'
    );
});

test( 'Locked property applies class', function( assert ) {
    var component  = this.subject(),
        $component = this.render();

    assert.strictEqual(
        $component.hasClass( 'sl-calendar-locked' ),
        false,
        'Default rendered component does not have class "sl-calendar-locked"'
    );

    Ember.run( () => {
        component.set( 'locked', true );
    });

    assert.ok(
        $component.hasClass( 'sl-calendar-locked' ),
        'Locked, rendered component has class "sl-calendar-locked"'
    );
});

test( 'Lock mode prevents changing state', function( assert ) {
    var component          = this.subject({ locked: true }),
        initialDecadeStart = component.get( 'decadeStart' ),
        initialMonth       = component.get( 'currentMonth' ),
        initialViewMode    = component.get( 'viewMode' ),
        initialYear        = component.get( 'currentYear' );

    component.send( 'changeDecade', 1 );
    assert.equal(
        initialDecadeStart,
        component.get( 'decadeStart' ),
        'Value decadeStart is unchanged from actions.changeDecade'
    );

    component.send( 'changeMonth', 1 );
    assert.equal(
        initialMonth,
        component.get( 'currentMonth' ),
        'Value currentMonth is unchanged from actions.changeMonth'
    );

    component.send( 'changeYear', 1 );
    assert.equal(
        initialYear,
        component.get( 'currentYear' ),
        'Value currentYear is unchanged from actions.changeYear'
    );

    component.send( 'setMonth', initialMonth + 1 );
    assert.equal(
        initialMonth,
        component.get( 'currentMonth' ),
        'Value currentMonth is unchanged from actions.setMonth'
    );

    component.send( 'setView', 'something' );
    assert.equal(
        initialViewMode,
        component.get( 'viewMode' ),
        'Value viewMode is unchanged from actions.setView'
    );

    component.send( 'setYear', initialYear + 1 );
    assert.equal(
        initialYear,
        component.get( 'currentYear' ),
        'Value currentYear is unchanged from actions.setYear'
    );
});

test( 'Clicking a day with a valid content value sends data', function( assert ) {
    var testDay   = 1,
        testMonth = 1,
        testYear  = 2015,
        testDate  = new Date( testYear, testMonth - 1, testDay ),
        component = this.subject({
            action       : 'test',
            content      : [ { date: testDate } ],
            currentMonth : testMonth,
            currentYear  : testYear,

            targetObject: {
                test: dateContent => {
                    assert.equal(
                        dateContent[ 0 ].date,
                        testDate,
                        'Date content received'
                    );
                }
            }
        }),
        $component = this.render();

    assert.expect( 1 );
    $component.find( '.active.day' ).trigger( 'click' );
});

test( 'changeDecade action works', function( assert ) {
    var component = this.subject({ currentYear: 2015 });

    assert.equal(
        component.get( 'decadeStart' ),
        2010,
        'Initial decadeStart is expected value'
    );

    assert.equal(
        component.get( 'decadeEnd' ),
        2019,
        'Initial decadeEnd is expected value'
    );

    Ember.run( () => { component.send( 'changeDecade', 1 ); } );

    assert.equal(
        component.get( 'decadeStart' ),
        2020,
        'Altered decadeStart is expected value'
    );

    assert.equal(
        component.get( 'decadeEnd' ),
        2029,
        'Altered decadeEnd is expected value'
    );
});

test( 'changeMonth action works', function( assert ) {
    var component = this.subject({ currentMonth: 1 });

    assert.equal(
        component.get( 'currentMonth' ),
        1,
        'Initial currentMonth is expected value'
    );

    Ember.run( () => { component.send( 'changeMonth', 1 ); } );

    assert.equal(
        component.get( 'currentMonth' ),
        2,
        'Altered currentMonth is expected value'
    );
});

test( 'changeYear action works', function ( assert ) {
    var component = this.subject({ currentYear: 2015 });

    assert.equal(
        component.get( 'currentYear' ),
        2015,
        'Initial currentYear is expected value'
    );

    Ember.run( () => { component.send( 'changeYear', 1 ); } );

    assert.equal(
        component.get( 'currentYear' ),
        2016,
        'Altered currentYear is expected value'
    );
});

test( 'Decrementing month from January causes year to decrement', function( assert ) {
    var component = this.subject({
            currentMonth : 1,
            currentYear  : 2015
        });

    Ember.run( () => { component.send( 'changeMonth', -1 ); } );

    assert.equal(
        component.get( 'currentYear' ),
        2014,
        'currentYear is decremented'
    );
});

test( 'Incrementing month from December causes year to increment', function( assert ) {
    var component = this.subject({
            currentMonth : 12,
            currentYear  : 2015
        });

    Ember.run( () => { component.send( 'changeMonth', 1 ); } );

    assert.equal(
        component.get( 'currentYear' ),
        2016,
        'currentYear is incremented'
    );
});

test( 'Setting dateValuePath works', function( assert ) {
    var $component;

    this.subject({
        content       : [ { test: new Date(2015, 0, 1) } ],
        currentMonth  : 1,
        currentYear   : 2015,
        dateValuePath : 'test'
    });

    $component = this.render();

    assert.equal(
        $component.find( '.active.day' ).text(),
        '1',
        'Active day is expected text value'
    );
});

test( 'Number of days in month is valid', function( assert ) {
    var component = this.subject();

    assert.ok(
        component.get( 'daysInMonth' ) > 0,
        'Days in current month is a non-zero number'
    );
});

test( 'Decade range is correctly based on currentYear', function( assert ) {
    var component = this.subject({ currentYear: 2023 });

    assert.equal(
        component.get( 'decadeStart' ),
        2020,
        'decadeStart is expected value'
    );

    assert.equal(
        component.get( 'decadeEnd' ),
        2029,
        'decadeEnd is expected value'
    );
});

test( 'Months for year view are generated validly', function( assert ) {
    var component = this.subject();

    assert.equal(
        component.get( 'monthsInYearView' ).length,
        12,
        'Twelve months are created'
    );
});

test( 'Short weekday name is formatted correctly', function( assert ) {
    var component = this.subject();

    assert.equal(
        component.shortWeekDayName( 1 ),
        'Mo',
        'Monday weekday name is "Mo"'
    );
});

test( 'View mode is settable to "days"', function( assert ) {
    var component = this.subject({ viewMode: 'days' });

    assert.ok(
        component.get( 'viewingDays' ),
        'viewingDays is true when viewMode = "days"'
    );
});

test( 'View mode is settable to "months"', function( assert ) {
    var component = this.subject({ viewMode: 'months' });

    assert.ok(
        component.get( 'viewingMonths' ),
        'viewingMonths is true when viewMode = "months"'
    );
});

test( 'View mode is settable to "years"', function( assert ) {
    var component = this.subject({ viewMode: 'years' });

    assert.ok(
        component.get( 'viewingYears' ),
        'viewingYears is true when viewMode = "years"'
    );
});

test( 'Weeks for month view are assembled correctly', function( assert ) {
    var component = this.subject();

    assert.ok(
        component.get( 'weeksInMonthView' ).length > 0,
        'A number of weeks were generated greater than zero'
    );
});

test( 'Years for decade view are assembled correctly', function( assert ) {
    var component = this.subject();

    assert.equal(
        component.get( 'yearsInDecadeView' ).length,
        12,
        'Twelve years were generated for the decade view'
    );
});
<commit_msg>Unit test improvements per PR#321 comments<commit_after>import Ember from 'ember';
import { moduleForComponent, test } from 'ember-qunit';

moduleForComponent( 'sl-calendar', 'Unit - component: sl-calendar', {
    needs: [
        'component:sl-calendar-day',
        'component:sl-calendar-month',
        'component:sl-calendar-year',
        'template:components/sl-calendar-day',
        'template:components/sl-calendar-month',
        'template:components/sl-calendar-year'
    ]
});

test( 'Default class name is present', function( assert ) {
    assert.ok(
        this.$().hasClass( 'sl-calendar' ),
        'Default rendered component has class "sl-calendar"'
    );
});

test( 'Locked property applies class', function( assert ) {
    var component = this.subject();

    assert.strictEqual(
        this.$().hasClass( 'sl-calendar-locked' ),
        false,
        'Default rendered component does not have class "sl-calendar-locked"'
    );

    Ember.run( () => {
        component.set( 'locked', true );
    });

    assert.ok(
        this.$().hasClass( 'sl-calendar-locked' ),
        'Locked, rendered component has class "sl-calendar-locked"'
    );
});

test( 'Lock mode prevents changing state', function( assert ) {
    var component          = this.subject({ locked: true }),
        initialDecadeStart = component.get( 'decadeStart' ),
        initialMonth       = component.get( 'currentMonth' ),
        initialViewMode    = component.get( 'viewMode' ),
        initialYear        = component.get( 'currentYear' );

    component.send( 'changeDecade', 1 );
    assert.equal(
        initialDecadeStart,
        component.get( 'decadeStart' ),
        'Value decadeStart is unchanged from actions.changeDecade'
    );

    component.send( 'changeMonth', 1 );
    assert.equal(
        initialMonth,
        component.get( 'currentMonth' ),
        'Value currentMonth is unchanged from actions.changeMonth'
    );

    component.send( 'changeYear', 1 );
    assert.equal(
        initialYear,
        component.get( 'currentYear' ),
        'Value currentYear is unchanged from actions.changeYear'
    );

    component.send( 'setMonth', initialMonth + 1 );
    assert.equal(
        initialMonth,
        component.get( 'currentMonth' ),
        'Value currentMonth is unchanged from actions.setMonth'
    );

    component.send( 'setView', 'something' );
    assert.equal(
        initialViewMode,
        component.get( 'viewMode' ),
        'Value viewMode is unchanged from actions.setView'
    );

    component.send( 'setYear', initialYear + 1 );
    assert.equal(
        initialYear,
        component.get( 'currentYear' ),
        'Value currentYear is unchanged from actions.setYear'
    );
});

test( 'Clicking a day with a valid content value sends data', function( assert ) {
    var testDay   = 1,
        testMonth = 1,
        testYear  = 2015,
        testDate  = new Date( testYear, testMonth - 1, testDay );

    this.subject({
        action       : 'test',
        content      : [ { date: testDate } ],
        currentMonth : testMonth,
        currentYear  : testYear,

        targetObject: {
            test: dateContent => {
                assert.equal(
                    dateContent[ 0 ].date,
                    testDate,
                    'Date content received'
                );
            }
        }
    });

    this.$( '.active.day' ).trigger( 'click' );
});

test( 'changeDecade action works', function( assert ) {
    var component = this.subject({ currentYear: 2015 });

    assert.equal(
        component.get( 'decadeStart' ),
        2010,
        'Initial decadeStart is expected value'
    );

    assert.equal(
        component.get( 'decadeEnd' ),
        2019,
        'Initial decadeEnd is expected value'
    );

    Ember.run( () => { component.send( 'changeDecade', 1 ); } );

    assert.equal(
        component.get( 'decadeStart' ),
        2020,
        'Altered decadeStart is expected value'
    );

    assert.equal(
        component.get( 'decadeEnd' ),
        2029,
        'Altered decadeEnd is expected value'
    );
});

test( 'changeMonth action works', function( assert ) {
    var component = this.subject({ currentMonth: 1 });

    assert.equal(
        component.get( 'currentMonth' ),
        1,
        'Initial currentMonth is expected value'
    );

    Ember.run( () => { component.send( 'changeMonth', 1 ); } );

    assert.equal(
        component.get( 'currentMonth' ),
        2,
        'Altered currentMonth is expected value'
    );
});

test( 'changeYear action works', function ( assert ) {
    var component = this.subject({ currentYear: 2015 });

    assert.equal(
        component.get( 'currentYear' ),
        2015,
        'Initial currentYear is expected value'
    );

    Ember.run( () => { component.send( 'changeYear', 1 ); } );

    assert.equal(
        component.get( 'currentYear' ),
        2016,
        'Altered currentYear is expected value'
    );
});

test( 'Decrementing month from January causes year to decrement', function( assert ) {
    var component = this.subject({
            currentMonth : 1,
            currentYear  : 2015
        });

    Ember.run( () => { component.send( 'changeMonth', -1 ); } );

    assert.equal(
        component.get( 'currentYear' ),
        2014,
        'currentYear is decremented'
    );
});

test( 'Incrementing month from December causes year to increment', function( assert ) {
    var component = this.subject({
            currentMonth : 12,
            currentYear  : 2015
        });

    Ember.run( () => { component.send( 'changeMonth', 1 ); } );

    assert.equal(
        component.get( 'currentYear' ),
        2016,
        'currentYear is incremented'
    );
});

test( 'Setting dateValuePath works', function( assert ) {
    this.subject({
        content       : [ { test: new Date(2015, 0, 1) } ],
        currentMonth  : 1,
        currentYear   : 2015,
        dateValuePath : 'test'
    });

    assert.equal(
        this.$( '.active.day' ).text(),
        '1',
        'Active day is expected text value'
    );
});

test( 'Number of days in month is valid', function( assert ) {
    var component = this.subject();

    assert.ok(
        component.get( 'daysInMonth' ) > 0,
        'Days in current month is a non-zero number'
    );
});

test( 'Decade range is correctly based on currentYear', function( assert ) {
    var component = this.subject({ currentYear: 2023 });

    assert.equal(
        component.get( 'decadeStart' ),
        2020,
        'decadeStart is expected value'
    );

    assert.equal(
        component.get( 'decadeEnd' ),
        2029,
        'decadeEnd is expected value'
    );
});

test( 'Months for year view are generated validly', function( assert ) {
    var component = this.subject();

    assert.equal(
        component.get( 'monthsInYearView' ).length,
        12,
        'Twelve months are created'
    );
});

test( 'Short weekday name is formatted correctly', function( assert ) {
    var component = this.subject();

    assert.equal(
        component.shortWeekDayName( 1 ),
        'Mo',
        'Monday weekday name is "Mo"'
    );
});

test( 'View mode is settable to "days"', function( assert ) {
    var component = this.subject({ viewMode: 'days' });

    assert.ok(
        component.get( 'viewingDays' ),
        'viewingDays is true when viewMode = "days"'
    );
});

test( 'View mode is settable to "months"', function( assert ) {
    var component = this.subject({ viewMode: 'months' });

    assert.ok(
        component.get( 'viewingMonths' ),
        'viewingMonths is true when viewMode = "months"'
    );
});

test( 'View mode is settable to "years"', function( assert ) {
    var component = this.subject({ viewMode: 'years' });

    assert.ok(
        component.get( 'viewingYears' ),
        'viewingYears is true when viewMode = "years"'
    );
});

test( 'Weeks for month view are assembled correctly', function( assert ) {
    var component = this.subject();

    assert.ok(
        component.get( 'weeksInMonthView' ).length > 0,
        'A number of weeks were generated greater than zero'
    );
});

test( 'Years for decade view are assembled correctly', function( assert ) {
    var component = this.subject();

    assert.equal(
        component.get( 'yearsInDecadeView' ).length,
        12,
        'Twelve years were generated for the decade view'
    );
});
<|endoftext|>


<commit_before>/* Description:
 *   Implements reset behaviour to a default URL
 *
 * Dependencies:
 *   None
 *
 * Configuration:
 *   DEFAULT_URL
 *
 * Commands:
 *   reset - Pushes the default url to the screen
 *
 * Author:
 *    lonnen
 */
module.exports = function(corsica) {
  corsica.on('content', function(msg, promise) {
    promise.fulfill(
      process.env.DEFAULT_URL || "http://i.imgur.com/SBvarB8.gif"
    );
  });
};
<commit_msg>refine plugin spec<commit_after>/* Description:
 *   pushes a default URL to screens when /reset is hit
 *
 * Dependencies:
 *   None
 *
 * Configuration:
 *   DEFAULT_URL
 *
 * Author:
 *    lonnen
 */
module.exports = function(corsica) {
  corsica.on('reset', function(content, promise) {
    promise.fulfill(
      process.env.DEFAULT_URL || "http://i.imgur.com/SBvarB8.gif"
    );
  });
};
<|endoftext|>


<commit_before>/* Modernizr 2.7.1 (Custom Build) | MIT & BSD
 * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderradius-boxshadow-flexbox-csstransforms3d-csstransitions-draganddrop-hashchange-history-localstorage-websockets-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes
 */
;

window.Modernizr = (function( window, document, undefined ) {

    var version = '2.7.1',

        Modernizr = {},

        docElement = document.documentElement,

        mod = 'modernizr',
        modElem = document.createElement(mod),
        mStyle = modElem.style,

        inputElem  ,

        toString = {}.toString,

        prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),

        omPrefixes = 'Webkit Moz O ms',

        cssomPrefixes = omPrefixes.split(' '),

        domPrefixes = omPrefixes.toLowerCase().split(' '),

        tests = {},
        inputs = {},
        attrs = {},

        classes = [],

        slice = classes.slice,

        featureName,

        injectElementWithStyles = function( rule, callback, nodes, testnames ) {

            var style, ret, node, docOverflow,
                div = document.createElement('div'),
                body = document.body,
                fakeBody = body || document.createElement('body');

            if ( parseInt(nodes, 10) ) {
                while ( nodes-- ) {
                    node = document.createElement('div');
                    node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
                    div.appendChild(node);
                }
            }

            style = ['','<style id="s', mod, '">', rule, '</style>'].join('');
            div.id = mod;
            (body ? div : fakeBody).innerHTML += style;
            fakeBody.appendChild(div);
            if ( !body ) {
                fakeBody.style.background = '';
                fakeBody.style.overflow = 'hidden';
                docOverflow = docElement.style.overflow;
                docElement.style.overflow = 'hidden';
                docElement.appendChild(fakeBody);
            }

            ret = callback(div, rule);
            if ( !body ) {
                fakeBody.parentNode.removeChild(fakeBody);
                docElement.style.overflow = docOverflow;
            } else {
                div.parentNode.removeChild(div);
            }

            return !!ret;

        },

        isEventSupported = (function() {

            var TAGNAMES = {
                'select': 'input', 'change': 'input',
                'submit': 'form', 'reset': 'form',
                'error': 'img', 'load': 'img', 'abort': 'img'
            };

            function isEventSupported( eventName, element ) {

                element = element || document.createElement(TAGNAMES[eventName] || 'div');
                eventName = 'on' + eventName;

                var isSupported = eventName in element;

                if ( !isSupported ) {
                    if ( !element.setAttribute ) {
                        element = document.createElement('div');
                    }
                    if ( element.setAttribute && element.removeAttribute ) {
                        element.setAttribute(eventName, '');
                        isSupported = is(element[eventName], 'function');

                        if ( !is(element[eventName], 'undefined') ) {
                            element[eventName] = undefined;
                        }
                        element.removeAttribute(eventName);
                    }
                }

                element = null;
                return isSupported;
            }
            return isEventSupported;
        })(),

        _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;

    if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
        hasOwnProp = function (object, property) {
            return _hasOwnProperty.call(object, property);
        };
    }
    else {
        hasOwnProp = function (object, property) {
            return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
        };
    }

    if (!Function.prototype.bind) {
        Function.prototype.bind = function bind(that) {

            var target = this;

            if (typeof target != "function") {
                throw new TypeError();
            }

            var args = slice.call(arguments, 1),
                bound = function () {

                    if (this instanceof bound) {

                        var F = function(){};
                        F.prototype = target.prototype;
                        var self = new F();

                        var result = target.apply(
                            self,
                            args.concat(slice.call(arguments))
                        );
                        if (Object(result) === result) {
                            return result;
                        }
                        return self;

                    } else {

                        return target.apply(
                            that,
                            args.concat(slice.call(arguments))
                        );

                    }

                };

            return bound;
        };
    }

    function setCss( str ) {
        mStyle.cssText = str;
    }

    function setCssAll( str1, str2 ) {
        return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
    }

    function is( obj, type ) {
        return typeof obj === type;
    }

    function contains( str, substr ) {
        return !!~('' + str).indexOf(substr);
    }

    function testProps( props, prefixed ) {
        for ( var i in props ) {
            var prop = props[i];
            if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
                return prefixed == 'pfx' ? prop : true;
            }
        }
        return false;
    }

    function testDOMProps( props, obj, elem ) {
        for ( var i in props ) {
            var item = obj[props[i]];
            if ( item !== undefined) {

                if (elem === false) return props[i];

                if (is(item, 'function')){
                    return item.bind(elem || obj);
                }

                return item;
            }
        }
        return false;
    }

    function testPropsAll( prop, prefixed, elem ) {

        var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
            props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');

        if(is(prefixed, "string") || is(prefixed, "undefined")) {
            return testProps(props, prefixed);

        } else {
            props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
            return testDOMProps(props, prefixed, elem);
        }
    }    tests['flexbox'] = function() {
        return testPropsAll('flexWrap');
    };    tests['hashchange'] = function() {
        return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
    };

    tests['history'] = function() {
        return !!(window.history && history.pushState);
    };

    tests['draganddrop'] = function() {
        var div = document.createElement('div');
        return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
    };

    tests['websockets'] = function() {
        return 'WebSocket' in window || 'MozWebSocket' in window;
    };

    tests['backgroundsize'] = function() {
        return testPropsAll('backgroundSize');
    };    tests['borderradius'] = function() {
        return testPropsAll('borderRadius');
    };

    tests['boxshadow'] = function() {
        return testPropsAll('boxShadow');
    };
    tests['csstransforms3d'] = function() {

        var ret = !!testPropsAll('perspective');

        if ( ret && 'webkitPerspective' in docElement.style ) {

            injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
                ret = node.offsetLeft === 9 && node.offsetHeight === 3;
            });
        }
        return ret;
    };

    tests['csstransitions'] = function() {
        return testPropsAll('transition');
    };

    tests['fontface'] = function() {
        var bool;

        injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
            var style = document.getElementById('smodernizr'),
                sheet = style.sheet || style.styleSheet,
                cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';

            bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
        });

        return bool;
    };    tests['localstorage'] = function() {
        try {
            localStorage.setItem(mod, mod);
            localStorage.removeItem(mod);
            return true;
        } catch(e) {
            return false;
        }
    };

    for ( var feature in tests ) {
        if ( hasOwnProp(tests, feature) ) {
            featureName  = feature.toLowerCase();
            Modernizr[featureName] = tests[feature]();

            classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
        }
    }

    Modernizr.addTest = function ( feature, test ) {
        if ( typeof feature == 'object' ) {
            for ( var key in feature ) {
                if ( hasOwnProp( feature, key ) ) {
                    Modernizr.addTest( key, feature[ key ] );
                }
            }
        } else {

            feature = feature.toLowerCase();

            if ( Modernizr[feature] !== undefined ) {
                return Modernizr;
            }

            test = typeof test == 'function' ? test() : test;

            if (typeof enableClasses !== "undefined" && enableClasses) {
                docElement.className += ' ' + (test ? '' : 'no-') + feature;
            }
            Modernizr[feature] = test;

        }

        return Modernizr;
    };

    setCss('');
    modElem = inputElem = null;

    Modernizr._version      = version;

    Modernizr._prefixes     = prefixes;
    Modernizr._domPrefixes  = domPrefixes;
    Modernizr._cssomPrefixes  = cssomPrefixes;

    Modernizr.hasEvent      = isEventSupported;

    Modernizr.testProp      = function(prop){
        return testProps([prop]);
    };

    Modernizr.testAllProps  = testPropsAll;

    Modernizr.testStyles    = injectElementWithStyles;
    return Modernizr;

})(this, this.document);
;<commit_msg>Wrapped script in closure<commit_after>/* Modernizr 2.7.1 (Custom Build) | MIT & BSD
 * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderradius-boxshadow-flexbox-csstransforms3d-csstransitions-draganddrop-hashchange-history-localstorage-websockets-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes
 */

(function() {

    window.Modernizr = (function( window, document, undefined ) {

        var version = '2.7.1',

            Modernizr = {},

            docElement = document.documentElement,

            mod = 'modernizr',
            modElem = document.createElement(mod),
            mStyle = modElem.style,

            inputElem  ,

            toString = {}.toString,

            prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),

            omPrefixes = 'Webkit Moz O ms',

            cssomPrefixes = omPrefixes.split(' '),

            domPrefixes = omPrefixes.toLowerCase().split(' '),

            tests = {},
            inputs = {},
            attrs = {},

            classes = [],

            slice = classes.slice,

            featureName,

            injectElementWithStyles = function( rule, callback, nodes, testnames ) {

                var style, ret, node, docOverflow,
                    div = document.createElement('div'),
                    body = document.body,
                    fakeBody = body || document.createElement('body');

                if ( parseInt(nodes, 10) ) {
                    while ( nodes-- ) {
                        node = document.createElement('div');
                        node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
                        div.appendChild(node);
                    }
                }

                style = ['','<style id="s', mod, '">', rule, '</style>'].join('');
                div.id = mod;
                (body ? div : fakeBody).innerHTML += style;
                fakeBody.appendChild(div);
                if ( !body ) {
                    fakeBody.style.background = '';
                    fakeBody.style.overflow = 'hidden';
                    docOverflow = docElement.style.overflow;
                    docElement.style.overflow = 'hidden';
                    docElement.appendChild(fakeBody);
                }

                ret = callback(div, rule);
                if ( !body ) {
                    fakeBody.parentNode.removeChild(fakeBody);
                    docElement.style.overflow = docOverflow;
                } else {
                    div.parentNode.removeChild(div);
                }

                return !!ret;

            },

            isEventSupported = (function() {

                var TAGNAMES = {
                    'select': 'input', 'change': 'input',
                    'submit': 'form', 'reset': 'form',
                    'error': 'img', 'load': 'img', 'abort': 'img'
                };

                function isEventSupported( eventName, element ) {

                    element = element || document.createElement(TAGNAMES[eventName] || 'div');
                    eventName = 'on' + eventName;

                    var isSupported = eventName in element;

                    if ( !isSupported ) {
                        if ( !element.setAttribute ) {
                            element = document.createElement('div');
                        }
                        if ( element.setAttribute && element.removeAttribute ) {
                            element.setAttribute(eventName, '');
                            isSupported = is(element[eventName], 'function');

                            if ( !is(element[eventName], 'undefined') ) {
                                element[eventName] = undefined;
                            }
                            element.removeAttribute(eventName);
                        }
                    }

                    element = null;
                    return isSupported;
                }
                return isEventSupported;
            })(),

            _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;

        if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
            hasOwnProp = function (object, property) {
                return _hasOwnProperty.call(object, property);
            };
        }
        else {
            hasOwnProp = function (object, property) {
                return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
            };
        }

        if (!Function.prototype.bind) {
            Function.prototype.bind = function bind(that) {

                var target = this;

                if (typeof target != "function") {
                    throw new TypeError();
                }

                var args = slice.call(arguments, 1),
                    bound = function () {

                        if (this instanceof bound) {

                            var F = function(){};
                            F.prototype = target.prototype;
                            var self = new F();

                            var result = target.apply(
                                self,
                                args.concat(slice.call(arguments))
                            );
                            if (Object(result) === result) {
                                return result;
                            }
                            return self;

                        } else {

                            return target.apply(
                                that,
                                args.concat(slice.call(arguments))
                            );

                        }

                    };

                return bound;
            };
        }

        function setCss( str ) {
            mStyle.cssText = str;
        }

        function setCssAll( str1, str2 ) {
            return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
        }

        function is( obj, type ) {
            return typeof obj === type;
        }

        function contains( str, substr ) {
            return !!~('' + str).indexOf(substr);
        }

        function testProps( props, prefixed ) {
            for ( var i in props ) {
                var prop = props[i];
                if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
                    return prefixed == 'pfx' ? prop : true;
                }
            }
            return false;
        }

        function testDOMProps( props, obj, elem ) {
            for ( var i in props ) {
                var item = obj[props[i]];
                if ( item !== undefined) {

                    if (elem === false) return props[i];

                    if (is(item, 'function')){
                        return item.bind(elem || obj);
                    }

                    return item;
                }
            }
            return false;
        }

        function testPropsAll( prop, prefixed, elem ) {

            var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
                props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');

            if(is(prefixed, "string") || is(prefixed, "undefined")) {
                return testProps(props, prefixed);

            } else {
                props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
                return testDOMProps(props, prefixed, elem);
            }
        }    tests['flexbox'] = function() {
            return testPropsAll('flexWrap');
        };    tests['hashchange'] = function() {
            return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
        };

        tests['history'] = function() {
            return !!(window.history && history.pushState);
        };

        tests['draganddrop'] = function() {
            var div = document.createElement('div');
            return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
        };

        tests['websockets'] = function() {
            return 'WebSocket' in window || 'MozWebSocket' in window;
        };

        tests['backgroundsize'] = function() {
            return testPropsAll('backgroundSize');
        };    tests['borderradius'] = function() {
            return testPropsAll('borderRadius');
        };

        tests['boxshadow'] = function() {
            return testPropsAll('boxShadow');
        };
        tests['csstransforms3d'] = function() {

            var ret = !!testPropsAll('perspective');

            if ( ret && 'webkitPerspective' in docElement.style ) {

                injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
                    ret = node.offsetLeft === 9 && node.offsetHeight === 3;
                });
            }
            return ret;
        };

        tests['csstransitions'] = function() {
            return testPropsAll('transition');
        };

        tests['fontface'] = function() {
            var bool;

            injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
                var style = document.getElementById('smodernizr'),
                    sheet = style.sheet || style.styleSheet,
                    cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';

                bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
            });

            return bool;
        };    tests['localstorage'] = function() {
            try {
                localStorage.setItem(mod, mod);
                localStorage.removeItem(mod);
                return true;
            } catch(e) {
                return false;
            }
        };

        for ( var feature in tests ) {
            if ( hasOwnProp(tests, feature) ) {
                featureName  = feature.toLowerCase();
                Modernizr[featureName] = tests[feature]();

                classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
            }
        }

        Modernizr.addTest = function ( feature, test ) {
            if ( typeof feature == 'object' ) {
                for ( var key in feature ) {
                    if ( hasOwnProp( feature, key ) ) {
                        Modernizr.addTest( key, feature[ key ] );
                    }
                }
            } else {

                feature = feature.toLowerCase();

                if ( Modernizr[feature] !== undefined ) {
                    return Modernizr;
                }

                test = typeof test == 'function' ? test() : test;

                if (typeof enableClasses !== "undefined" && enableClasses) {
                    docElement.className += ' ' + (test ? '' : 'no-') + feature;
                }
                Modernizr[feature] = test;

            }

            return Modernizr;
        };

        setCss('');
        modElem = inputElem = null;

        Modernizr._version      = version;

        Modernizr._prefixes     = prefixes;
        Modernizr._domPrefixes  = domPrefixes;
        Modernizr._cssomPrefixes  = cssomPrefixes;

        Modernizr.hasEvent      = isEventSupported;

        Modernizr.testProp      = function(prop){
            return testProps([prop]);
        };

        Modernizr.testAllProps  = testPropsAll;

        Modernizr.testStyles    = injectElementWithStyles;
        return Modernizr;

    })(this, this.document);

})();<|endoftext|>


<commit_before>var fs = require('fs');
var url = require('url');
var pem = require('pem');
var https = require('https');
var join = require('path').join;
var cheerio = require('cheerio');
var request = require('request');
var thunkify = require('thunkify');

// CRX packaging module, instantiated with the `new` keyword
var Extension = require('crx');

// POST /generate
module.exports = function *() {
    // Get target URL from input
    var url = this.request.body.url;

    // Build .crx config for the provided URL
    var crxConfig = yield exports.buildCrxConfig(url);

    // Generate the .crx file based on the config
    var crxBuffer = yield exports.generateCrx(crxConfig);

    // Send it to the browser (save to disk)
    yield exports.sendCrx(this, crxConfig, crxBuffer);
}

exports.buildCrxConfig = function *(targetUrl) {
    // Bad input?
    if (! targetUrl) {
        throw new Error('Please provide a URL to continue.');
    }

    // Parse URL (to retrieve hostname and verify its validity)
    var parsedUrl = url.parse(targetUrl);

    // Parse failed?
    if (! parsedUrl || ! parsedUrl.protocol || parsedUrl.protocol.indexOf('http') == -1) {
        throw new Error('Please provide a valid URL for your extension. (It must start with http(s)://)');
    }

    // Prepare crx object with default values
    var crxConfig = {
        url: targetUrl,
        parsedUrl: parsedUrl,
        title: parsedUrl.hostname,
        filename: parsedUrl.hostname + '.crx'
    };

    // Prepare request (send fake browser user-agent header)
    var req = {
        url: crxConfig.url,
        headers: {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36'
        }
    };

    // Page HTML response
    var res;

    // Execute GET request to provided URL
    // May fail for internal URLs, continue anyway
    try {
        res = yield thunkify(request)(req);
    }
    catch(exc) {
        // Return fallback config
        return crxConfig;
    }

    // Load DOM into Cheerio (HTML parser)
    var dom = cheerio.load(res[0].body);

    // Extract extension title from the dom's <title> tag
    crxConfig.title = dom('title').text().trim() || crxConfig.parsedUrl.hostname;

    // Extract .crx icon from page's shortcut-icon <link> element
    crxConfig.icon = dom('link[rel="icon"], link[rel="shortcut icon"]').attr('href');

    // Custom icons per host (workaround for no <link> tag)
    switch(crxConfig.parsedUrl.host) {
        case 'web.whatsapp.com':
            crxConfig.icon = 'https://web.whatsapp.com/favicon-64x64.ico';
            break;
        case 'keep.google.com':
            crxConfig.icon = 'https://ssl.gstatic.com/keep/icon_128.png';
            break;
        case 'messenger.com':
            // Fix weird 0x8234 chars in FB messenger <title>
            crxConfig.title = 'Messenger'
            crxConfig.icon = 'https://lh5.ggpht.com/0VYAvZLR9YhosF-thqm8xl8EWsCfrEY_uk2og2f59K8IOx5TfPsXjFVwxaHVnUbuEjc=w300';
            break;
    }

    // Return crx config
    return crxConfig;
}

exports.generateCrx = function* (crxConfig) {
    // Generate pem certificate
    var cert = yield thunkify(pem.createCertificate)({days:365 * 10, selfSigned:true});

    // Init new .crx extension with our private key
    var crx = new Extension({privateKey: cert.clientKey});

    // Load extension manifest and default icon
    yield crx.load(join(__dirname, "../lib/extension/files"));

    // Set extension title to extension URL's <title>
    crx.manifest.name = crxConfig.title;

    // Ask for permission to access the specified URL
    crx.manifest.app.urls.push(crxConfig.url);

    // Configure the launch behavior of the extension to the specfied URL
    crx.manifest.app.launch.web_url = crxConfig.url;

    // Got a favicon?
    if (crxConfig.icon) {
        // Download it and overwrite default icon
        yield exports.downloadIcon(crxConfig, crx);
    }
    else
    {
        // Set a placeholder icon instead
        yield exports.setPlaceholderIcon(crxConfig, crx);
    }

    // Pack the extension into a .crx and return its buffer
    var crxBuffer = yield crx.pack();

    // Return buffer
    return crxBuffer;
}

exports.downloadIcon = function*(crxConfig, crx) {
    // Convert relative icon path to absolute
    var absoluteIconUrl = url.resolve(crxConfig.url, crxConfig.icon);

    // Resolve succeeded?
    if (absoluteIconUrl) {
        // Set download path as current extension icon's path
        var downloadPath = crx.path + "/" + crx.manifest.icons['128'];

        // Download it
        yield exports.downloadFile(absoluteIconUrl, downloadPath);
    }
}

exports.setPlaceholderIcon = function*(crxConfig, crx) {
    // Grab first char (hopefully a letter)
    var letter = crxConfig.parsedUrl.hostname.substring(0, 1).toUpperCase();

    // Not an English letter?
    if (! letter.match(/[A-Z]/) ) {
        return;
    }

    // Build path to placeholder letter icon
    var copyFromPath = join(__dirname, '../lib/extension/icons/fallback/' + letter + '.png');

    // Set target copy path as current extension icon's path
    var copyToPath = crx.path + "/" + crx.manifest.icons['128'];

    // Copy the local file and override extension's default icon
    yield exports.copyLocalFile(copyFromPath, copyToPath);
}

exports.sendCrx = function*(request, crxConfig, crxBuffer) {
    // Set content-type to .crx extension mime type
    request.set('content-type', 'application/x-chrome-extension');

    // Set extension filename
    request.set('content-disposition', 'attachment; filename=' + crxConfig.filename);

    // Set the request body to the .crx file buffer
    request.body = crxBuffer;
}

exports.downloadFile = function(url, filePath) {
    // Promisify the request
    return new Promise(function(resolve, reject) {
        try {
            // Create write stream
            var stream = fs.createWriteStream(filePath);

            // Wait for finish event
            stream.on('finish', function() {
                // Resolve the promise
                return resolve(true);
            });

            // Pipe the request to a file
            return request(url).pipe(stream);
        } catch (e) {
            // Failed
            return reject(e);
        }
    });
};

exports.copyLocalFile = function(from, to) {
    // Promisify the request
    return new Promise(function(resolve, reject) {
        try {
            // Create write stream
            var writeStream = fs.createWriteStream(to);

            // Wait for finish event
            writeStream.on('finish', function() {
                // Resolve the promise
                return resolve(true);
            });

            // Pipe the "from" stream into the "to" stream
            fs.createReadStream(from).pipe(writeStream);
        } catch (e) {
            // Failed
            return reject(e);
        }
    });
};<commit_msg>Add a high-res icon for YouTube, handle 'www.' hostnames<commit_after>var fs = require('fs');
var url = require('url');
var pem = require('pem');
var https = require('https');
var join = require('path').join;
var cheerio = require('cheerio');
var request = require('request');
var thunkify = require('thunkify');

// CRX packaging module, instantiated with the `new` keyword
var Extension = require('crx');

// POST /generate
module.exports = function *() {
    // Get target URL from input
    var url = this.request.body.url;

    // Build .crx config for the provided URL
    var crxConfig = yield exports.buildCrxConfig(url);

    // Generate the .crx file based on the config
    var crxBuffer = yield exports.generateCrx(crxConfig);

    // Send it to the browser (save to disk)
    yield exports.sendCrx(this, crxConfig, crxBuffer);
}

exports.buildCrxConfig = function *(targetUrl) {
    // Bad input?
    if (! targetUrl) {
        throw new Error('Please provide a URL to continue.');
    }

    // Parse URL (to retrieve hostname and verify its validity)
    var parsedUrl = url.parse(targetUrl);

    // Parse failed?
    if (! parsedUrl || ! parsedUrl.protocol || parsedUrl.protocol.indexOf('http') == -1) {
        throw new Error('Please provide a valid URL for your extension. (It must start with http(s)://)');
    }

    // Prepare crx object with default values
    var crxConfig = {
        url: targetUrl,
        parsedUrl: parsedUrl,
        title: parsedUrl.hostname,
        filename: parsedUrl.hostname + '.crx'
    };

    // Prepare request (send fake browser user-agent header)
    var req = {
        url: crxConfig.url,
        headers: {
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36'
        }
    };

    // Page HTML response
    var res;

    // Execute GET request to provided URL
    // May fail for internal URLs, continue anyway
    try {
        res = yield thunkify(request)(req);
    }
    catch(exc) {
        // Return fallback config
        return crxConfig;
    }

    // Load DOM into Cheerio (HTML parser)
    var dom = cheerio.load(res[0].body);

    // Extract extension title from the dom's <title> tag
    crxConfig.title = dom('title').text().trim() || crxConfig.parsedUrl.hostname;

    // Extract .crx icon from page's shortcut-icon <link> element
    crxConfig.icon = dom('link[rel="icon"], link[rel="shortcut icon"]').attr('href');

    // Custom icons per host (workaround for no <link> tag)
    switch(crxConfig.parsedUrl.host.replace('www.', '')) {
        case 'web.whatsapp.com':
            crxConfig.icon = 'https://web.whatsapp.com/favicon-64x64.ico';
            break;
        case 'keep.google.com':
            crxConfig.icon = 'https://ssl.gstatic.com/keep/icon_128.png';
            break;
        case 'messenger.com':
            // Fix weird 0x8234 chars in FB messenger <title>
            crxConfig.title = 'Messenger'
            crxConfig.icon = 'https://lh5.ggpht.com/0VYAvZLR9YhosF-thqm8xl8EWsCfrEY_uk2og2f59K8IOx5TfPsXjFVwxaHVnUbuEjc=w300';
            break;
        case 'youtube.com':
            crxConfig.icon = 'https://www.gstatic.com/images/icons/material/product/2x/youtube_64dp.png';
            break;
    }

    // Return crx config
    return crxConfig;
}

exports.generateCrx = function* (crxConfig) {
    // Generate pem certificate
    var cert = yield thunkify(pem.createCertificate)({days:365 * 10, selfSigned:true});

    // Init new .crx extension with our private key
    var crx = new Extension({privateKey: cert.clientKey});

    // Load extension manifest and default icon
    yield crx.load(join(__dirname, "../lib/extension/files"));

    // Set extension title to extension URL's <title>
    crx.manifest.name = crxConfig.title;

    // Ask for permission to access the specified URL
    crx.manifest.app.urls.push(crxConfig.url);

    // Configure the launch behavior of the extension to the specfied URL
    crx.manifest.app.launch.web_url = crxConfig.url;

    // Got a favicon?
    if (crxConfig.icon) {
        // Download it and overwrite default icon
        yield exports.downloadIcon(crxConfig, crx);
    }
    else
    {
        // Set a placeholder icon instead
        yield exports.setPlaceholderIcon(crxConfig, crx);
    }

    // Pack the extension into a .crx and return its buffer
    var crxBuffer = yield crx.pack();

    // Return buffer
    return crxBuffer;
}

exports.downloadIcon = function*(crxConfig, crx) {
    // Convert relative icon path to absolute
    var absoluteIconUrl = url.resolve(crxConfig.url, crxConfig.icon);

    // Resolve succeeded?
    if (absoluteIconUrl) {
        // Set download path as current extension icon's path
        var downloadPath = crx.path + "/" + crx.manifest.icons['128'];

        // Download it
        yield exports.downloadFile(absoluteIconUrl, downloadPath);
    }
}

exports.setPlaceholderIcon = function*(crxConfig, crx) {
    // Grab first char (hopefully a letter)
    var letter = crxConfig.parsedUrl.hostname.substring(0, 1).toUpperCase();

    // Not an English letter?
    if (! letter.match(/[A-Z]/) ) {
        return;
    }

    // Build path to placeholder letter icon
    var copyFromPath = join(__dirname, '../lib/extension/icons/fallback/' + letter + '.png');

    // Set target copy path as current extension icon's path
    var copyToPath = crx.path + "/" + crx.manifest.icons['128'];

    // Copy the local file and override extension's default icon
    yield exports.copyLocalFile(copyFromPath, copyToPath);
}

exports.sendCrx = function*(request, crxConfig, crxBuffer) {
    // Set content-type to .crx extension mime type
    request.set('content-type', 'application/x-chrome-extension');

    // Set extension filename
    request.set('content-disposition', 'attachment; filename=' + crxConfig.filename);

    // Set the request body to the .crx file buffer
    request.body = crxBuffer;
}

exports.downloadFile = function(url, filePath) {
    // Promisify the request
    return new Promise(function(resolve, reject) {
        try {
            // Create write stream
            var stream = fs.createWriteStream(filePath);

            // Wait for finish event
            stream.on('finish', function() {
                // Resolve the promise
                return resolve(true);
            });

            // Pipe the request to a file
            return request(url).pipe(stream);
        } catch (e) {
            // Failed
            return reject(e);
        }
    });
};

exports.copyLocalFile = function(from, to) {
    // Promisify the request
    return new Promise(function(resolve, reject) {
        try {
            // Create write stream
            var writeStream = fs.createWriteStream(to);

            // Wait for finish event
            writeStream.on('finish', function() {
                // Resolve the promise
                return resolve(true);
            });

            // Pipe the "from" stream into the "to" stream
            fs.createReadStream(from).pipe(writeStream);
        } catch (e) {
            // Failed
            return reject(e);
        }
    });
};<|endoftext|>


<commit_before>import {
  stringifyQuery
} from 'uni-shared/query'

import {
  initHooks,
  initUnknownHooks,
  PAGE_EVENT_HOOKS
} from 'uni-wrapper/util'

import parseComponent from 'uni-platform/runtime/wrapper/component-parser'

const hooks = [
  'onShow',
  'onHide',
  'onUnload'
]

hooks.push(...PAGE_EVENT_HOOKS)

export default function parseBasePage (vuePageOptions, {
  isPage,
  initRelation
}) {
  const pageOptions = parseComponent(vuePageOptions, {
    isPage,
    initRelation
  })

  initHooks(pageOptions.methods, hooks, vuePageOptions)

  pageOptions.methods.onLoad = function (query) {
    this.options = query
    const copyQuery = Object.assign({}, query)
    delete copyQuery.__id__
    this.$page = {
      fullPath: '/' + (this.route || this.is) + stringifyQuery(copyQuery)
    }
    this.$vm.$mp.query = query // 兼容 mpvue
    this.$vm.__call_hook('onLoad', query)
  }
  initUnknownHooks(pageOptions.methods, vuePageOptions, ['onReady'])

  return pageOptions
}
<commit_msg>fix(mp-baidu): onInit not trigger (question/154352)<commit_after>import {
  stringifyQuery
} from 'uni-shared/query'

import {
  initHooks,
  initUnknownHooks,
  PAGE_EVENT_HOOKS
} from 'uni-wrapper/util'

import parseComponent from 'uni-platform/runtime/wrapper/component-parser'

const hooks = [
  'onShow',
  'onHide',
  'onUnload'
]

hooks.push(...PAGE_EVENT_HOOKS)

export default function parseBasePage (vuePageOptions, {
  isPage,
  initRelation
}) {
  const pageOptions = parseComponent(vuePageOptions, {
    isPage,
    initRelation
  })

  initHooks(pageOptions.methods, hooks, vuePageOptions)

  pageOptions.methods.onLoad = function (query) {
    this.options = query
    const copyQuery = Object.assign({}, query)
    delete copyQuery.__id__
    this.$page = {
      fullPath: '/' + (this.route || this.is) + stringifyQuery(copyQuery)
    }
    this.$vm.$mp.query = query // 兼容 mpvue
    this.$vm.__call_hook('onLoad', query)
  }
  if (__PLATFORM__ === 'mp-baidu') {
    initUnknownHooks(pageOptions.methods, vuePageOptions, ['onInit', 'onReady'])
  } else {
    initUnknownHooks(pageOptions.methods, vuePageOptions, ['onReady'])
  }

  return pageOptions
}
<|endoftext|>


<commit_before>// Magic scroll things.
// This binds cool animations to the scroll level in such a way that the
// animations' progress can be controlled by scrolling. This does what
// ScrollMagic does except without the bugs.

const elem = {
  body: document.body,

  header: document.getElementsByTagName('header')[0],
  headerTitle: document.getElementsByTagName('h1')[0],
  downIndicator: document.getElementsByClassName('down-indicator')[0],

  laptop: document.getElementsByClassName('laptop')[0],
  laptopContent: document.getElementsByClassName('laptop-content')[0],
  laptopBase: document.getElementsByClassName('laptop-base')[0],

  laptopsContainer: document.getElementsByClassName('laptops-container')[0],
  laptopsStretcher: document.getElementsByClassName('laptops-stretcher')[0],
};

// HEADER TRANSITION LOGIC =========================================================================

function setHeaderElementsPinned(fixed) {
  // Switch between fixed and absolute, pinning elements in the appropriate place
  [elem.headerTitle, elem.laptop].forEach((element) => {
    /* eslint-disable no-param-reassign */
    element.style.position = fixed ? 'fixed' : 'absolute';
    element.style.top = fixed ? '50vh' : `${window.innerHeight}px`;
    /* eslint-enable no-param-reassign */
  });
}

function updateHeaderElements(progress) {
  // Blends two values based on "progress" made between them.
  function tween(a, b) {
    return a + ((b - a) * progress);
  }

  // FIT MAIN HEADER TO LAPTOP SCREEN

  // Values for tweening. [x, y, w, h]. All values are viewport-relative.

  const initialPos = [50, 50, 100, 100]; // The starting position (fixed)
  const destinationPos = [               // The shrunk position (still fixed)
    50,
    50 - ((100 * elem.laptopBase.offsetHeight) / window.innerHeight / 2),
    (100 * elem.laptopContent.offsetWidth) / window.innerWidth,
    (100 * elem.laptopContent.offsetHeight) / window.innerHeight,
  ];
  const restingPos = [                   // The shrunk position (absolute now)
    50,
    destinationPos[1] + 50,
    destinationPos[2],
    destinationPos[3],
  ];

  // NOTE: Left is ignored since it's constant

  const fixedTop = tween(initialPos[1], destinationPos[1]);
  const top = progress < 1 ? fixedTop : restingPos[1];
  elem.header.style.top = `${top}vh`;

  const width = tween(initialPos[2], destinationPos[2]);
  elem.header.style.width = `${width}vw`;

  const height = tween(initialPos[3], destinationPos[3]);
  elem.header.style.height = `${height}vh`;

  elem.header.style.position = progress < 1 ? 'fixed' : 'absolute';

  // MISCELLANEOUS

  // Update opacity of down indicator
  elem.downIndicator.style.opacity = 1 - progress;
  // Reduce font size of my name
  elem.headerTitle.style.fontSize = `${tween(5, 3.5)}vw`;

  // ADJUST CANVAS SETTINGS

  const canvasScale = ( // Mean of X scale difference and Y scale difference
    (window.gol.elem.offsetWidth / window.innerWidth) +
    (window.gol.elem.offsetHeight / window.innerHeight)
  ) / 2;
  window.gol.idealCellSize = 20 * canvasScale;
  window.gol.needsSizeUpdate = true;
}

// BACKGROUND TRANSITION LOGIC =====================================================================

function updateBackgroundColor(progress) {
  const grad1A = window.parseColor('#5EFCE8');
  const grad1B = window.parseColor('#736EFE');

  const grad2A = window.parseColor('#16222A');
  const grad2B = window.parseColor('#3A6073');

  const interpolate = (a, b, amount) => ({
    r: Math.floor((a.r * (1 - progress)) + (b.r * amount)),
    g: Math.floor((a.g * (1 - progress)) + (b.g * amount)),
    b: Math.floor((a.b * (1 - progress)) + (b.b * amount)),
  });

  const getCssGradString = (a, b, deg = 135) =>
    `linear-gradient(${deg}deg, rgb(${a.r}, ${a.g}, ${a.b}), rgb(${b.r}, ${b.g}, ${b.b}))`;

  const calcA = interpolate(grad1A, grad2A, progress);
  const calcB = interpolate(grad1B, grad2B, progress);
  elem.body.style.backgroundImage = getCssGradString(calcA, calcB);
}

// SCROLL LISTENER =================================================================================

function onscroll() {
  const scroll = window.scrollY;

  // Header

  switch (true) {
    case (scroll < 5): {
      setHeaderElementsPinned(true);
      requestAnimationFrame(() => updateHeaderElements(0));
      break;
    }

    case (scroll < window.innerHeight / 2): {
      setHeaderElementsPinned(true);
      const headerProgress = scroll / (window.innerHeight / 2);
      requestAnimationFrame(() => updateHeaderElements(headerProgress));
      break;
    }

    default: {
      setHeaderElementsPinned(false);
      requestAnimationFrame(() => updateHeaderElements(1));
    }
  }

  // Background

  switch (true) {
    case (scroll < window.innerHeight * 0.75): {
      updateBackgroundColor(0);
      break;
    }

    case (scroll > window.innerHeight * 1.25): {
      updateBackgroundColor(1);
      break;
    }

    default: {
      const bgProgress = (scroll - (window.innerHeight * 0.75)) / (window.innerHeight * 0.5);
      updateBackgroundColor(bgProgress);
    }
  }

  // Carousel

  const largerScreenDimension = Math.max(window.innerWidth, window.innerHeight);

  // Adjust carousel position
  const start = elem.laptopsStretcher.offsetTop;
  const end = start + (largerScreenDimension * 1.5);

  const carouselProgress = (scroll - start) / (end - start);
  requestAnimationFrame(() => {
    window.carousel.position = carouselProgress * window.carousel.maxIndex;
  });

  // Adjust min and max progress of particles

  const rotLimit = window.LaptopCarousel.rotLimit;

  const firstLaptopRot = +window.carousel.laptopsByIndex[0].rotateZ.replace('deg', '');
  const firstLaptopProgress = (firstLaptopRot + rotLimit) / (2 * rotLimit);
  window.particles.maxProgress = firstLaptopProgress;

  const lastLaptopRot = +window.carousel.laptopsByIndex[window.carousel.maxIndex].rotateZ.replace('deg', '');
  const lastLaptopProgress = (lastLaptopRot + rotLimit) / (2 * rotLimit);
  window.particles.minProgress = lastLaptopProgress;
}

document.addEventListener('scroll', onscroll);
window.addEventListener('resize', onscroll);
document.addEventListener('DOMContentLoaded', onscroll);
<commit_msg>Muter gradient in second section<commit_after>// Magic scroll things.
// This binds cool animations to the scroll level in such a way that the
// animations' progress can be controlled by scrolling. This does what
// ScrollMagic does except without the bugs.

const elem = {
  body: document.body,

  header: document.getElementsByTagName('header')[0],
  headerTitle: document.getElementsByTagName('h1')[0],
  downIndicator: document.getElementsByClassName('down-indicator')[0],

  laptop: document.getElementsByClassName('laptop')[0],
  laptopContent: document.getElementsByClassName('laptop-content')[0],
  laptopBase: document.getElementsByClassName('laptop-base')[0],

  laptopsContainer: document.getElementsByClassName('laptops-container')[0],
  laptopsStretcher: document.getElementsByClassName('laptops-stretcher')[0],
};

// HEADER TRANSITION LOGIC =========================================================================

function setHeaderElementsPinned(fixed) {
  // Switch between fixed and absolute, pinning elements in the appropriate place
  [elem.headerTitle, elem.laptop].forEach((element) => {
    /* eslint-disable no-param-reassign */
    element.style.position = fixed ? 'fixed' : 'absolute';
    element.style.top = fixed ? '50vh' : `${window.innerHeight}px`;
    /* eslint-enable no-param-reassign */
  });
}

function updateHeaderElements(progress) {
  // Blends two values based on "progress" made between them.
  function tween(a, b) {
    return a + ((b - a) * progress);
  }

  // FIT MAIN HEADER TO LAPTOP SCREEN

  // Values for tweening. [x, y, w, h]. All values are viewport-relative.

  const initialPos = [50, 50, 100, 100]; // The starting position (fixed)
  const destinationPos = [               // The shrunk position (still fixed)
    50,
    50 - ((100 * elem.laptopBase.offsetHeight) / window.innerHeight / 2),
    (100 * elem.laptopContent.offsetWidth) / window.innerWidth,
    (100 * elem.laptopContent.offsetHeight) / window.innerHeight,
  ];
  const restingPos = [                   // The shrunk position (absolute now)
    50,
    destinationPos[1] + 50,
    destinationPos[2],
    destinationPos[3],
  ];

  // NOTE: Left is ignored since it's constant

  const fixedTop = tween(initialPos[1], destinationPos[1]);
  const top = progress < 1 ? fixedTop : restingPos[1];
  elem.header.style.top = `${top}vh`;

  const width = tween(initialPos[2], destinationPos[2]);
  elem.header.style.width = `${width}vw`;

  const height = tween(initialPos[3], destinationPos[3]);
  elem.header.style.height = `${height}vh`;

  elem.header.style.position = progress < 1 ? 'fixed' : 'absolute';

  // MISCELLANEOUS

  // Update opacity of down indicator
  elem.downIndicator.style.opacity = 1 - progress;
  // Reduce font size of my name
  elem.headerTitle.style.fontSize = `${tween(5, 3.5)}vw`;

  // ADJUST CANVAS SETTINGS

  const canvasScale = ( // Mean of X scale difference and Y scale difference
    (window.gol.elem.offsetWidth / window.innerWidth) +
    (window.gol.elem.offsetHeight / window.innerHeight)
  ) / 2;
  window.gol.idealCellSize = 20 * canvasScale;
  window.gol.needsSizeUpdate = true;
}

// BACKGROUND TRANSITION LOGIC =====================================================================

function updateBackgroundColor(progress) {
  const grad1A = window.parseColor('#5EFCE8');
  const grad1B = window.parseColor('#736EFE');

  const grad2A = window.parseColor('#16222A');
  const grad2B = window.parseColor('#4A5070');

  const interpolate = (a, b, amount) => ({
    r: Math.floor((a.r * (1 - progress)) + (b.r * amount)),
    g: Math.floor((a.g * (1 - progress)) + (b.g * amount)),
    b: Math.floor((a.b * (1 - progress)) + (b.b * amount)),
  });

  const getCssGradString = (a, b, deg = 135) =>
    `linear-gradient(${deg}deg, rgb(${a.r}, ${a.g}, ${a.b}), rgb(${b.r}, ${b.g}, ${b.b}))`;

  const calcA = interpolate(grad1A, grad2A, progress);
  const calcB = interpolate(grad1B, grad2B, progress);
  elem.body.style.backgroundImage = getCssGradString(calcA, calcB);
}

// SCROLL LISTENER =================================================================================

function onscroll() {
  const scroll = window.scrollY;

  // Header

  switch (true) {
    case (scroll < 5): {
      setHeaderElementsPinned(true);
      requestAnimationFrame(() => updateHeaderElements(0));
      break;
    }

    case (scroll < window.innerHeight / 2): {
      setHeaderElementsPinned(true);
      const headerProgress = scroll / (window.innerHeight / 2);
      requestAnimationFrame(() => updateHeaderElements(headerProgress));
      break;
    }

    default: {
      setHeaderElementsPinned(false);
      requestAnimationFrame(() => updateHeaderElements(1));
    }
  }

  // Background

  switch (true) {
    case (scroll < window.innerHeight * 0.75): {
      updateBackgroundColor(0);
      break;
    }

    case (scroll > window.innerHeight * 1.25): {
      updateBackgroundColor(1);
      break;
    }

    default: {
      const bgProgress = (scroll - (window.innerHeight * 0.75)) / (window.innerHeight * 0.5);
      updateBackgroundColor(bgProgress);
    }
  }

  // Carousel

  const largerScreenDimension = Math.max(window.innerWidth, window.innerHeight);

  // Adjust carousel position
  const start = elem.laptopsStretcher.offsetTop;
  const end = start + (largerScreenDimension * 1.5);

  const carouselProgress = (scroll - start) / (end - start);
  requestAnimationFrame(() => {
    window.carousel.position = carouselProgress * window.carousel.maxIndex;
  });

  // Adjust min and max progress of particles

  const rotLimit = window.LaptopCarousel.rotLimit;

  const firstLaptopRot = +window.carousel.laptopsByIndex[0].rotateZ.replace('deg', '');
  const firstLaptopProgress = (firstLaptopRot + rotLimit) / (2 * rotLimit);
  window.particles.maxProgress = firstLaptopProgress;

  const lastLaptopRot = +window.carousel.laptopsByIndex[window.carousel.maxIndex].rotateZ.replace('deg', '');
  const lastLaptopProgress = (lastLaptopRot + rotLimit) / (2 * rotLimit);
  window.particles.minProgress = lastLaptopProgress;
}

document.addEventListener('scroll', onscroll);
window.addEventListener('resize', onscroll);
document.addEventListener('DOMContentLoaded', onscroll);
<|endoftext|>