<commit_before>module.exports = function (app, express, passport, logger, root) {

    var nconf = require('nconf'),
        cachify = require('connect-cachify'),
        winston = require('winston'),
        path = require('path'),
        requestLogger = require('winston-request-logger');

    if (!root) {
      root = path.normalize(__dirname + '/..');
    }
    nconf.file({ file: root + '/gebo.json' });

    // load assets node from configuration file.
//    var assets = nconf.get('assets') || {};

    // Development Configuration
    app.configure('development', 'test', function(){
        // register the request logger
        app.use(requestLogger.create(logger))
        app.set('DEBUG', true)
        app.use(express.errorHandler({ dumpExceptions: true, showStack: true }))
    });

    // Production Configuration
    app.configure('production', function(){
        app.set('DEBUG', false)
        app.use(express.errorHandler())
    });

    /**
     * allowCrossDomain
     */
    var allowCrossDomain = function(req, res, next) {
        res.header('Access-Control-Allow-Origin', '*');
        res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
        res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

        if ('OPTIONS' === req.method) {
          res.send(200);
        }
        else {
          next();
        }
    };

    /**
     * Redirect to HTTPS
     *
     * Peter Lyons, 2013-4-5
     * http://stackoverflow.com/questions/15813677/https-redirection-for-all-routes-node-js-express-security-concerns
     */
    function requireHttps(req, res, next) {
        if (!req.secure) {
          var url = nconf.get('domain') + ':' + nconf.get('httpsPort') + req.url;
          console.log(url);
          return res.redirect(url);
        }
        next();
      }

    // Cachify Asset Configuration
//    app.use(cachify.setup(assets, {
//        root: root + '/public',
//        production: nconf.get('cachify')
//    }));

    // Global Configuration
    app.configure(function(){

        app.use(allowCrossDomain);
        app.set('views', root + '/views');
        app.set('view engine', 'jade');
        app.set('view options', { layout: false });
        app.use(express.cookieParser());
        app.use(express.bodyParser());
        app.use(express.methodOverride());
        app.use(express.static(root + '/public'));
        app.use(express.favicon(root + '/favicon.ico'));
        app.use(express.session({secret: 'keyboard cat'}));
        app.use(requireHttps);
        // Initialize Passport!  Also use passport.session() middleware, to support
        // persistent login sessions (recommended).
        app.use(passport.initialize());
        app.use(passport.session());
        app.use(app.router);
    });

//    return app;
};
<commit_msg>Restore cachify stuff<commit_after>module.exports = function (app, express, passport, logger, root) {

    var nconf = require('nconf'),
        cachify = require('connect-cachify'),
        winston = require('winston'),
        path = require('path'),
        requestLogger = require('winston-request-logger');

    if (!root) {
      root = path.normalize(__dirname + '/..');
    }
    nconf.file({ file: root + '/gebo.json' });

    // load assets node from configuration file.
    var assets = nconf.get('assets') || {};

    // Development Configuration
    app.configure('development', 'test', function(){
        // register the request logger
        app.use(requestLogger.create(logger))
        app.set('DEBUG', true)
        app.use(express.errorHandler({ dumpExceptions: true, showStack: true }))
    });

    // Production Configuration
    app.configure('production', function(){
        app.set('DEBUG', false)
        app.use(express.errorHandler())
    });

    /**
     * allowCrossDomain
     */
    var allowCrossDomain = function(req, res, next) {
        res.header('Access-Control-Allow-Origin', '*');
        res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
        res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

        if ('OPTIONS' === req.method) {
          res.send(200);
        }
        else {
          next();
        }
    };

    /**
     * Redirect to HTTPS
     *
     * Peter Lyons, 2013-4-5
     * http://stackoverflow.com/questions/15813677/https-redirection-for-all-routes-node-js-express-security-concerns
     */
    function requireHttps(req, res, next) {
        if (!req.secure) {
          var url = nconf.get('domain') + ':' + nconf.get('httpsPort') + req.url;
          console.log(url);
          return res.redirect(url);
        }
        next();
      }

    // Cachify Asset Configuration
    app.use(cachify.setup(assets, {
        root: root + '/public',
        production: nconf.get('cachify')
    }));

    // Global Configuration
    app.configure(function(){

        app.use(allowCrossDomain);
        app.set('views', root + '/views');
        app.set('view engine', 'jade');
        app.set('view options', { layout: false });
        app.use(express.cookieParser());
        app.use(express.bodyParser());
        app.use(express.methodOverride());
        app.use(express.static(root + '/public'));
        app.use(express.favicon(root + '/favicon.ico'));
        app.use(express.session({secret: 'keyboard cat'}));
        app.use(requireHttps);
        // Initialize Passport!  Also use passport.session() middleware, to support
        // persistent login sessions (recommended).
        app.use(passport.initialize());
        app.use(passport.session());
        app.use(app.router);
    });

//    return app;
};
<|endoftext|>


<commit_before>/**
 * @author WestLangley / http://github.com/WestLangley
 *
 */

import {
	InstancedInterleavedBuffer,
	InterleavedBufferAttribute,
	Line3,
	Matrix4,
	Mesh,
	Vector3,
	Vector4
} from "../../../build/three.module.js";
import { LineSegmentsGeometry } from "../lines/LineSegmentsGeometry.js";
import { LineMaterial } from "../lines/LineMaterial.js";

var LineSegments2 = function ( geometry, material ) {

	Mesh.call( this );

	this.type = 'LineSegments2';

	this.geometry = geometry !== undefined ? geometry : new LineSegmentsGeometry();
	this.material = material !== undefined ? material : new LineMaterial( { color: Math.random() * 0xffffff } );

};

LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {

	constructor: LineSegments2,

	isLineSegments2: true,

	computeLineDistances: ( function () { // for backwards-compatability, but could be a method of LineSegmentsGeometry...

		var start = new Vector3();
		var end = new Vector3();

		return function computeLineDistances() {

			var geometry = this.geometry;

			var instanceStart = geometry.attributes.instanceStart;
			var instanceEnd = geometry.attributes.instanceEnd;
			var lineDistances = new Float32Array( 2 * instanceStart.data.count );

			for ( var i = 0, j = 0, l = instanceStart.data.count; i < l; i ++, j += 2 ) {

				start.fromBufferAttribute( instanceStart, i );
				end.fromBufferAttribute( instanceEnd, i );

				lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
				lineDistances[ j + 1 ] = lineDistances[ j ] + start.distanceTo( end );

			}

			var instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1

			geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
			geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1

			return this;

		};

	}() ),

	raycast: ( function () {

		var start = new Vector4();
		var end = new Vector4();

		var ssOrigin = new Vector4();
		var ssOrigin3 = new Vector3();
		var mvMatrix = new Matrix4();
		var line = new Line3();
		var closestPoint = new Vector3();

		return function raycast( raycaster, intersects ) {

			if ( raycaster.camera === null ) {

				console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2.' );

			}

			var ray = raycaster.ray;
			var camera = raycaster.camera;
			var projectionMatrix = camera.projectionMatrix;

			var geometry = this.geometry;
			var material = this.material;
			var resolution = material.resolution;
			var lineWidth = material.linewidth;

			var instanceStart = geometry.attributes.instanceStart;
			var instanceEnd = geometry.attributes.instanceEnd;

			// ndc space [ - 0.5, 0.5 ]
			ray.at( 1, ssOrigin );
			ssOrigin.w = 1;
			ssOrigin.applyMatrix4( camera.matrixWorldInverse );
			ssOrigin.applyMatrix4( projectionMatrix );
			ssOrigin.multiplyScalar( 1 / ssOrigin.w );

			// screen space
			ssOrigin.x *= resolution.x / 2;
			ssOrigin.y *= resolution.y / 2;
			ssOrigin.z = 0;

			ssOrigin3.copy( ssOrigin );

			var matrixWorld = this.matrixWorld;
			mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );

			for ( var i = 0, l = instanceStart.count; i < l; i ++ ) {

				start.fromBufferAttribute( instanceStart, i );
				end.fromBufferAttribute( instanceEnd, i );

				start.w = 1;
				end.w = 1;

				// camera space
				start.applyMatrix4( mvMatrix );
				end.applyMatrix4( mvMatrix );

				// clip space
				start.applyMatrix4( projectionMatrix );
				end.applyMatrix4( projectionMatrix );

				// ndc space [ - 1.0, 1.0 ]
				start.multiplyScalar( 1 / start.w );
				end.multiplyScalar( 1 / end.w );

				// segment is behind camera near
				if ( start.z < - 1 && end.z < - 1 ) {

					continue;

				}

				// segment is in front of camera far
				if ( start.z > 1 && end.z > 1 ) {

					continue;

				}

				// screen space
				start.x *= resolution.x / 2;
				start.y *= resolution.y / 2;

				end.x *= resolution.x / 2;
				end.y *= resolution.y / 2;

				// create 2d segment
				line.start.copy( start );
				line.start.z = 0;

				line.end.copy( end );
				line.end.z = 0;

				// get closest point on ray to segment
				var param = line.closestPointToPointParameter( ssOrigin3, true );
				line.at( param, closestPoint );

				// check if the intersection point is within clip space
				var zPos = MathUtils.lerp( start.z, end.z, param );
				var isInClipSpace = zPos >= -1 && zPos <= 1;

				if ( isInClipSpace && ssOrigin3.distanceTo( closestPoint ) < lineWidth * 0.5 ) {

					line.start.fromBufferAttribute( instanceStart, i );
					line.end.fromBufferAttribute( instanceEnd, i );

					line.start.applyMatrix4( matrixWorld );
					line.end.applyMatrix4( matrixWorld );

					var pointOnLine = new Vector3();
					line.at( param, pointOnLine );

					var point = new Vector3();
					ray.closestPointToPoint( pointOnLine, point );

					intersects.push( {

						point: point,
						pointOnLine: pointOnLine,
						distance: ray.origin.distanceTo( point ),

						object: this,
						face: null,
						faceIndex: i,
						uv: null,
						uv2: null,

					} );

				}

			}

		}

	} () )

} );

export { LineSegments2 };
<commit_msg>js -> jsm<commit_after>/**
 * @author WestLangley / http://github.com/WestLangley
 *
 */

import {
	InstancedInterleavedBuffer,
	InterleavedBufferAttribute,
	Line3,
	Math as _Math,
	Matrix4,
	Mesh,
	Vector3,
	Vector4
} from "../../../build/three.module.js";
import { LineSegmentsGeometry } from "../lines/LineSegmentsGeometry.js";
import { LineMaterial } from "../lines/LineMaterial.js";

var LineSegments2 = function ( geometry, material ) {

	Mesh.call( this );

	this.type = 'LineSegments2';

	this.geometry = geometry !== undefined ? geometry : new LineSegmentsGeometry();
	this.material = material !== undefined ? material : new LineMaterial( { color: Math.random() * 0xffffff } );

};

LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {

	constructor: LineSegments2,

	isLineSegments2: true,

	computeLineDistances: ( function () { // for backwards-compatability, but could be a method of LineSegmentsGeometry...

		var start = new Vector3();
		var end = new Vector3();

		return function computeLineDistances() {

			var geometry = this.geometry;

			var instanceStart = geometry.attributes.instanceStart;
			var instanceEnd = geometry.attributes.instanceEnd;
			var lineDistances = new Float32Array( 2 * instanceStart.data.count );

			for ( var i = 0, j = 0, l = instanceStart.data.count; i < l; i ++, j += 2 ) {

				start.fromBufferAttribute( instanceStart, i );
				end.fromBufferAttribute( instanceEnd, i );

				lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ];
				lineDistances[ j + 1 ] = lineDistances[ j ] + start.distanceTo( end );

			}

			var instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1

			geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0
			geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1

			return this;

		};

	}() ),

	raycast: ( function () {

		var start = new Vector4();
		var end = new Vector4();

		var ssOrigin = new Vector4();
		var ssOrigin3 = new Vector3();
		var mvMatrix = new Matrix4();
		var line = new Line3();
		var closestPoint = new Vector3();

		return function raycast( raycaster, intersects ) {

			if ( raycaster.camera === null ) {

				console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2.' );

			}

			var ray = raycaster.ray;
			var camera = raycaster.camera;
			var projectionMatrix = camera.projectionMatrix;

			var geometry = this.geometry;
			var material = this.material;
			var resolution = material.resolution;
			var lineWidth = material.linewidth;

			var instanceStart = geometry.attributes.instanceStart;
			var instanceEnd = geometry.attributes.instanceEnd;

			// ndc space [ - 0.5, 0.5 ]
			ray.at( 1, ssOrigin );
			ssOrigin.w = 1;
			ssOrigin.applyMatrix4( camera.matrixWorldInverse );
			ssOrigin.applyMatrix4( projectionMatrix );
			ssOrigin.multiplyScalar( 1 / ssOrigin.w );

			// screen space
			ssOrigin.x *= resolution.x / 2;
			ssOrigin.y *= resolution.y / 2;
			ssOrigin.z = 0;

			ssOrigin3.copy( ssOrigin );

			var matrixWorld = this.matrixWorld;
			mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );

			for ( var i = 0, l = instanceStart.count; i < l; i ++ ) {

				start.fromBufferAttribute( instanceStart, i );
				end.fromBufferAttribute( instanceEnd, i );

				start.w = 1;
				end.w = 1;

				// camera space
				start.applyMatrix4( mvMatrix );
				end.applyMatrix4( mvMatrix );

				// clip space
				start.applyMatrix4( projectionMatrix );
				end.applyMatrix4( projectionMatrix );

				// ndc space [ - 1.0, 1.0 ]
				start.multiplyScalar( 1 / start.w );
				end.multiplyScalar( 1 / end.w );

				// skip the segment if it's outside the camera near and far planes
				var isBehindCameraNear = start.z < - 1 && end.z < - 1;
				var isPastCameraFar = start.z > 1 && end.z > 1;
				if ( isBehindCameraNear || isPastCameraFar ) {

					continue;

				}

				// screen space
				start.x *= resolution.x / 2;
				start.y *= resolution.y / 2;

				end.x *= resolution.x / 2;
				end.y *= resolution.y / 2;

				// create 2d segment
				line.start.copy( start );
				line.start.z = 0;

				line.end.copy( end );
				line.end.z = 0;

				// get closest point on ray to segment
				var param = line.closestPointToPointParameter( ssOrigin3, true );
				line.at( param, closestPoint );

				// check if the intersection point is within clip space
				var zPos = _Math.lerp( start.z, end.z, param );
				var isInClipSpace = zPos >= -1 && zPos <= 1;

				var isInside = ssOrigin3.distanceTo( closestPoint ) < lineWidth * 0.5;

				if ( isInClipSpace && isInside ) {

					line.start.fromBufferAttribute( instanceStart, i );
					line.end.fromBufferAttribute( instanceEnd, i );

					line.start.applyMatrix4( matrixWorld );
					line.end.applyMatrix4( matrixWorld );

					var pointOnLine = new Vector3();
					var point = new Vector3();

					ray.distanceSqToSegment( line.start, line.end, point, pointOnLine );

					intersects.push( {

						point: point,
						pointOnLine: pointOnLine,
						distance: ray.origin.distanceTo( point ),

						object: this,
						face: null,
						faceIndex: i,
						uv: null,
						uv2: null,

					} );

				}

			}

		}

	} () )

} );

export { LineSegments2 };
<|endoftext|>


<commit_before>$(function() {
  var ads = [
    {
      quote: "Take your icon game to the next level. Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_1_next_level&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },
    {
      quote: "Subset your icons, add your own, and serve up from a CDN. Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_2_all_value_add&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },
    {
      quote: "Make your icons load 10x faster! Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_3_faster_loading&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },
    {
      quote: "Looking for other great icon sets? Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_4_more_icons&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },
    {
      quote: "Need a custom icon in Font Awesome? Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_5_custom_icons&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },

    {
      quote: "So hot right now: Black Tie, the new multi-weight icon font from the maker of Font Awesome.",
      class: "black-tie",
      url: "https://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_1_so_hot&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    },
    {
      quote: "Black Tie, from the creator of Font Awesome. On sale at the Kickstarter price for a limited time.",
      class: "black-tie",
      url: "https://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_2_kickstarter&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    },
    {
      quote: "Get more Awesome: Black Tie, the new multi-weight icon font from the maker of Font Awesome.",
      class: "black-tie",
      url: "https://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_3_more_awesome&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    },
    {
      quote: "The new hotness from the maker of Font Awesome: Black Tie, the multi-weight icon font.",
      class: "black-tie",
      url: "https://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_4_new_hotness&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    },
    {
      quote: "Want clean, minimalist icons? Check out Black Tie, the new multi-weight icon font from the maker of Font Awesome.",
      class: "black-tie",
      url: "https://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_5_clean_minimalist&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    }
  ];

  selectFonticonsAd();

  // start the icon carousel
  $('#icon-carousel').carousel({
    interval: 5000
  });

  var $filter_by = $('#filter-by');

  // Filter icons
  if($filter_by.length) {
    var $filter_val = $('#filter-val');
    var $filter = $('#filter');
    var $other = $('#new, #web-application, #transportation, #gender, #form-control, #medical, #currency, #text-editor, #directional, #video-player, #brand, #file-type, #spinner, #payment, #chart');
    var $clear = $('#filter-clear');
    var $no_results = $('#no-search-results');

    var $icons = $('.filter-icon', $filter);

    // Add tab completion
    $filter_by.tabcomplete(filterSet, {
      arrowKeys: true
    });

    $clear.on('click', function(e) {
      e.preventDefault();
      $filter_by
        .val('')
        .trigger('input')
        .trigger('keyup')
        .focus();

      $clear.addClass('hide'); // Hide clear button
    });

    $filter_by.on('keyup', function() {
      var $this = $(this);
      var val = $this.val().toLowerCase();
      $filter.toggle(!!val);
      $other.toggle(!val);
      $clear.toggleClass('hide', !val);
      $filter_val.text(val);

      if(!val) return;

      var resultsCount = 0;
      $icons.each(function() {
        var filter = $(this).attr('data-filter').split('|');
        var show = inFilter(val, filter);
        if (!show) {
          if (val.slice(-1) === 's') {
            // Try to be smart. Make plural terms singular.
            show = inFilter(val.slice(0, -1), filter);
          }
        }
        if (show) resultsCount++;
        $(this).toggle(!!show);
      });

      if( resultsCount == 0 && val.length != 0 ) {
        $no_results.find('span').text(val);
        $no_results.show();
      } else {
        $no_results.hide();
      }
    });
  }

  function inFilter(val, filter) {
    for (var i = 0; i < filter.length; i++) {
      if (filter[i].match(val)) return true;
    }
    return false;
  }

  $filter_by
    .val('')
    .trigger('input')
    .trigger('keyup');

  if ($clear) {
    $clear.addClass('hide'); // Hide clear button
  }

  function selectFonticonsAd() {
    random_number = Math.floor( Math.random() * ads.length );
    random_ad = ads[random_number];

    $('#banner').addClass(random_ad.class);
    $('#rotating-message').html(random_ad.quote);
    $('#rotating-url').attr("href", random_ad.url);
    $('#rotating-url').html(random_ad.btn_text);
    $('#banner').collapse('show');
  }
});
<commit_msg>Removing HTTPS<commit_after>$(function() {
  var ads = [
    {
      quote: "Take your icon game to the next level. Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_1_next_level&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },
    {
      quote: "Subset your icons, add your own, and serve up from a CDN. Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_2_all_value_add&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },
    {
      quote: "Make your icons load 10x faster! Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_3_faster_loading&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },
    {
      quote: "Looking for other great icon sets? Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_4_more_icons&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },
    {
      quote: "Need a custom icon in Font Awesome? Check out Fonticons, from the maker of Font Awesome.",
      class: "fonticons",
      url: "https://fonticons.com/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_5_custom_icons&utm_campaign=promo_4.3_update",
      btn_text: "Gimme Some!"
    },

    {
      quote: "So hot right now: Black Tie, the new multi-weight icon font from the maker of Font Awesome.",
      class: "black-tie",
      url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_1_so_hot&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    },
    {
      quote: "Black Tie, from the creator of Font Awesome. On sale at the Kickstarter price for a limited time.",
      class: "black-tie",
      url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_2_kickstarter&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    },
    {
      quote: "Get more Awesome: Black Tie, the new multi-weight icon font from the maker of Font Awesome.",
      class: "black-tie",
      url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_3_more_awesome&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    },
    {
      quote: "The new hotness from the maker of Font Awesome: Black Tie, the multi-weight icon font.",
      class: "black-tie",
      url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_4_new_hotness&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    },
    {
      quote: "Want clean, minimalist icons? Check out Black Tie, the new multi-weight icon font from the maker of Font Awesome.",
      class: "black-tie",
      url: "http://blacktie.io/?utm_source=font_awesome_homepage&utm_medium=display&utm_content=ad_5_clean_minimalist&utm_campaign=promo_4.3_update",
      btn_text: "Buy it Now!"
    }
  ];

  selectFonticonsAd();

  // start the icon carousel
  $('#icon-carousel').carousel({
    interval: 5000
  });

  var $filter_by = $('#filter-by');

  // Filter icons
  if($filter_by.length) {
    var $filter_val = $('#filter-val');
    var $filter = $('#filter');
    var $other = $('#new, #web-application, #transportation, #gender, #form-control, #medical, #currency, #text-editor, #directional, #video-player, #brand, #file-type, #spinner, #payment, #chart');
    var $clear = $('#filter-clear');
    var $no_results = $('#no-search-results');

    var $icons = $('.filter-icon', $filter);

    // Add tab completion
    $filter_by.tabcomplete(filterSet, {
      arrowKeys: true
    });

    $clear.on('click', function(e) {
      e.preventDefault();
      $filter_by
        .val('')
        .trigger('input')
        .trigger('keyup')
        .focus();

      $clear.addClass('hide'); // Hide clear button
    });

    $filter_by.on('keyup', function() {
      var $this = $(this);
      var val = $this.val().toLowerCase();
      $filter.toggle(!!val);
      $other.toggle(!val);
      $clear.toggleClass('hide', !val);
      $filter_val.text(val);

      if(!val) return;

      var resultsCount = 0;
      $icons.each(function() {
        var filter = $(this).attr('data-filter').split('|');
        var show = inFilter(val, filter);
        if (!show) {
          if (val.slice(-1) === 's') {
            // Try to be smart. Make plural terms singular.
            show = inFilter(val.slice(0, -1), filter);
          }
        }
        if (show) resultsCount++;
        $(this).toggle(!!show);
      });

      if( resultsCount == 0 && val.length != 0 ) {
        $no_results.find('span').text(val);
        $no_results.show();
      } else {
        $no_results.hide();
      }
    });
  }

  function inFilter(val, filter) {
    for (var i = 0; i < filter.length; i++) {
      if (filter[i].match(val)) return true;
    }
    return false;
  }

  $filter_by
    .val('')
    .trigger('input')
    .trigger('keyup');

  if ($clear) {
    $clear.addClass('hide'); // Hide clear button
  }

  function selectFonticonsAd() {
    random_number = Math.floor( Math.random() * ads.length );
    random_ad = ads[random_number];

    $('#banner').addClass(random_ad.class);
    $('#rotating-message').html(random_ad.quote);
    $('#rotating-url').attr("href", random_ad.url);
    $('#rotating-url').html(random_ad.btn_text);
    $('#banner').collapse('show');
  }
});
<|endoftext|>


<commit_before>/**
 *
 * Draggable Grouping contributed by:  Muthukumar Selvarasu
 *  muthukumar{dot}se{at}gmail{dot}com
 *  github.com/muthukumarse/Slickgrid
 *
 * NOTES:
 *     This plugin provides the Draggable Grouping feature
 */

(function ($) {
  // Register namespace
  $.extend(true, window, {
    "Slick": {
      "DraggableGrouping": DraggableGrouping
    }
  });

  /***
   * A plugin to add Draggable Grouping feature.
   *
   * USAGE:
   *
   * Add the plugin .js & .css files and register it with the grid.
   *
   *
   * The plugin expose the following methods:
   *    destroy: used to destroy the plugin
   *    setDroppedGroups: provide option to set default grouping on loading
   *    clearDroppedGroups: provide option to clear grouping
   *    getSetupColumnReorder: its function to setup draggable feature agains Header Column, should be passed on grid option. Also possible to pass custom function
   *
   *
   * The plugin expose the following event(s):
   *    onGroupChanged: pass the grouped columns to who subscribed.
   *
   * @param options {Object} Options:
   *    deleteIconCssClass:  an extra CSS class to add to the delete button (default undefined), if deleteIconCssClass && deleteIconImage undefined then slick-groupby-remove-image class will be added
   *    deleteIconImage:     a url to the delete button image (default undefined)
   *    groupIconCssClass:   an extra CSS class to add to the grouping field hint  (default undefined)
   *    groupIconImage:      a url to the grouping field hint image (default undefined)
   *    dropPlaceHolderText:      option to specify set own placeholder note text
   *

   */

  function DraggableGrouping(options) {
    var _grid;
    var _gridUid;
    var _gridColumns;
    var _dataView;
    var dropbox;
    var dropboxPlaceholder;
    var groupToggler;
    var _self = this;
    var _defaults = {
    };
    var onGroupChanged = new Slick.Event();

    /**
     * Initialize plugin.
     */
    function init(grid) {
      options = $.extend(true, {}, _defaults, options);
      _grid = grid;
      _gridUid = _grid.getUID();
      _gridColumns =  _grid.getColumns();
      _dataView = _grid.getData();

      dropbox = $(_grid.getPreHeaderPanel());
      var dropPlaceHolderText = options.dropPlaceHolderText || 'Drop a column header here to group by the column';
      dropbox.html("
" + dropPlaceHolderText + "

");

      dropboxPlaceholder = dropbox.find(".slick-placeholder");
      groupToggler = dropbox.find(".slick-group-toggle-all");
      setupColumnDropbox();

      _grid.onHeaderCellRendered.subscribe(function (e, args) {
        var column = args.column;
        var node = args.node;
        if (!$.isEmptyObject(column.grouping)) {
          var groupableIcon = $("");
          if(options.groupIconCssClass) groupableIcon.addClass(options.groupIconCssClass)
          if(options.groupIconImage) groupableIcon.css("background", "url(" + options.groupIconImage + ") no-repeat center center");
          $(node).css('cursor', 'pointer').append(groupableIcon);
        }
      })

      for (var i = 0; i < _gridColumns.length; i++) {
        var columnId = _gridColumns[i].field;
        _grid.updateColumnHeader(columnId);
      }

    }

    function setupColumnReorder(grid, $headers, headerColumnWidthDiff, setColumns, setupColumnResize, columns, getColumnIndex, uid, trigger) {
      $headers.filter(":ui-sortable").sortable("destroy");
      var $headerDraggableGroupBy = $(grid.getPreHeaderPanel());
        $headers.sortable({
          distance: 3,
          cursor: "default",
          tolerance: "intersection",
          helper: "clone",
          placeholder: "slick-sortable-placeholder ui-state-default slick-header-column",
          forcePlaceholderSize: true,
          appendTo: "body",
          start: function(e, ui) {
            $(ui.helper).addClass("slick-header-column-active");
            $headerDraggableGroupBy.find(".slick-placeholder").show();
            $headerDraggableGroupBy.find(".slick-dropped-grouping").hide();
          },
          beforeStop: function(e, ui) {
            $(ui.helper).removeClass("slick-header-column-active");
            var hasDroppedColumn = $headerDraggableGroupBy.find(".slick-dropped-grouping").length;
            if(hasDroppedColumn > 0){
              $headerDraggableGroupBy.find(".slick-placeholder").hide();
              $headerDraggableGroupBy.find(".slick-dropped-grouping").show();
            }
          },
          stop: function(e) {
            if (!grid.getEditorLock().commitCurrentEdit()) {
              $(this).sortable("cancel");
              return;
            }
            var reorderedIds = $headers.sortable("toArray");
            var reorderedColumns = [];
            for (var i = 0; i < reorderedIds.length; i++) {
              reorderedColumns.push(columns[getColumnIndex(reorderedIds[i].replace(uid, ""))]);
            }
            setColumns(reorderedColumns);
            trigger(grid.onColumnsReordered, {
              grid: grid
            });
            e.stopPropagation();
            setupColumnResize();
          }
        });
    }

    /**
     * Destroy plugin.
     */
    function destroy() {
      onGroupChanged.unsubscribe();
    }

    function setColumns(col) {
      _gridColumns = col;
    }

    var emptyDropbox;

    function setupColumnDropbox() {
      dropbox.droppable({
        activeClass: "ui-state-default",
        hoverClass: "ui-state-hover",
        accept: ":not(.ui-sortable-helper)",
        deactivate: function(event, ui) {
          dropbox.removeClass("slick-header-column-denied");
        },
        drop: function(event, ui) {
          handleGroupByDrop(this, ui.draggable);
        },
        over: function(event, ui) {
          var id = (ui.draggable).attr('id').replace(_gridUid, "");
          _gridColumns.forEach(function(e, i, a) {
            if (e.id == id) {
              if (e.grouping == null) {
                dropbox.addClass("slick-header-column-denied");
              }
            }
          });
        }
      });
      dropbox.sortable({
        items: "div.slick-dropped-grouping",
        cursor: "default",
        tolerance: "pointer",
        helper: "clone",
        update: function(event, ui) {
          var sortArray = $(this).sortable('toArray', {
              attribute: 'data-id'
            }),
            newGroupingOrder = [];
          for (var i = 0, l = sortArray.length; i < l; i++) {
            for (var a = 0, b = columnsGroupBy.length; a < b; a++) {
              if (columnsGroupBy[a].id == sortArray[i]) {
                newGroupingOrder.push(columnsGroupBy[a]);
                break;
              }
            }
          }
          columnsGroupBy = newGroupingOrder;
          updateGroupBy();
        }
      });
      emptyDropbox = dropbox.html();

      groupToggler.on('click', function(e) {
        if (this.classList.contains('collapsed')) {
          this.classList.remove('collapsed');
          this.classList.add('expanded');
          _dataView.expandAllGroups();
        } else {
          this.classList.add('collapsed');
          this.classList.remove('expanded');
          _dataView.collapseAllGroups();
        }
      });
    }

    var columnsGroupBy = [];
    var groupBySorters = [];

    function handleGroupByDrop(container, column) {
      var columnid = column.attr('id').replace(_gridUid, "");
      var columnAllowed = true;
      columnsGroupBy.forEach(function(e, i, a) {
        if (e.id == columnid) {
          columnAllowed = false;
        }
      });
      if (columnAllowed) {
        _gridColumns.forEach(function(e, i, a) {
          if (e.id == columnid) {
            if (e.grouping != null && !$.isEmptyObject(e.grouping)) {
              var entry = $("
");
              var groupText = $("
" + column.text() + "
")
              groupText.appendTo(entry);
              var groupRemoveIcon = $("

")
              if(options.deleteIconCssClass) groupRemoveIcon.addClass(options.deleteIconCssClass);
              if(options.deleteIconImage) groupRemoveIcon.css("background", "url(" + options.deleteIconImage + ") no-repeat center right");
              if(!options.deleteIconCssClass && !options.deleteIconImage) groupRemoveIcon.addClass('slick-groupby-remove-image');
              groupRemoveIcon.appendTo(entry);

              $("
").appendTo(entry);
              entry.appendTo(container);
              addColumnGroupBy(e, column, container, entry);
              addGroupByRemoveClickHandler(e.id, container, column, entry);
            }
          }
        });
        groupToggler.css('display', 'block');
      }
    }

    function addColumnGroupBy(column) {
      columnsGroupBy.push(column);
      updateGroupBy();
    }

    function addGroupByRemoveClickHandler(id, container, column, entry) {
      var text = entry;
      $("#" + _gridUid + id + "_entry >.slick-groupby-remove").on('click', function() {
        $(this).off('click');
        removeGroupBy(id, column, text);
      });
    }

    function setDroppedGroups(groupingInfo) {
      groupingInfos = (groupingInfo instanceof Array) ? groupingInfo : [groupingInfo];
      dropboxPlaceholder.hide()
      for (var i = 0; i < groupingInfos.length; i++) {
        var column = $(_grid.getHeaderColumn(groupingInfos[i]));
        handleGroupByDrop(dropbox, column);
      }
    }
    function clearDroppedGroups() {
      columnsGroupBy = [];
      updateGroupBy();
      onGroupChanged.notify({ groupColumns: []})
      dropbox.find(".slick-dropped-grouping").remove();
      groupToggler.css("display", "none");
      dropboxPlaceholder.show()
    }

    function removeFromArray(arr) {
      var what, a = arguments,
        L = a.length,
        ax;
      while (L > 1 && arr.length) {
        what = a[--L];
        while ((ax = arr.indexOf(what)) != -1) {
          arr.splice(ax, 1);
        }
      }
      return arr;
    }

    function removeGroupBy(id, column, entry) {
      entry.remove();
      var groupby = [];
      _gridColumns.forEach(function(e, i, a) {
        groupby[e.id] = e;
      });
      removeFromArray(columnsGroupBy, groupby[id]);
      if(columnsGroupBy.length == 0){
        dropboxPlaceholder.show();
      }
      updateGroupBy();
    }

    function updateGroupBy() {
      if (columnsGroupBy.length == 0) {
        _dataView.setGrouping([]);
        return;
      }
      var groupingArray = [];
      columnsGroupBy.forEach(function(element, index, array) {
        groupingArray.push(element.grouping);
      });
      _dataView.setGrouping(groupingArray);
      /*
      collapseAllGroups();
      */
      onGroupChanged.notify({ groupColumns: groupingArray})
    }

    // Public API
    $.extend(this, {
      "init": init,
      "destroy": destroy,
      "onGroupChanged": onGroupChanged,
      "setDroppedGroups": setDroppedGroups,
      "clearDroppedGroups": clearDroppedGroups,
      "getSetupColumnReorder": setupColumnReorder,
    });
  }
})(jQuery);
<commit_msg>fixes issue #299, notify onGroupChanged even on empty array<commit_after>/**
 *
 * Draggable Grouping contributed by:  Muthukumar Selvarasu
 *  muthukumar{dot}se{at}gmail{dot}com
 *  github.com/muthukumarse/Slickgrid
 *
 * NOTES:
 *     This plugin provides the Draggable Grouping feature
 */

(function ($) {
  // Register namespace
  $.extend(true, window, {
    "Slick": {
      "DraggableGrouping": DraggableGrouping
    }
  });

  /***
   * A plugin to add Draggable Grouping feature.
   *
   * USAGE:
   *
   * Add the plugin .js & .css files and register it with the grid.
   *
   *
   * The plugin expose the following methods:
   *    destroy: used to destroy the plugin
   *    setDroppedGroups: provide option to set default grouping on loading
   *    clearDroppedGroups: provide option to clear grouping
   *    getSetupColumnReorder: its function to setup draggable feature agains Header Column, should be passed on grid option. Also possible to pass custom function
   *
   *
   * The plugin expose the following event(s):
   *    onGroupChanged: pass the grouped columns to who subscribed.
   *
   * @param options {Object} Options:
   *    deleteIconCssClass:  an extra CSS class to add to the delete button (default undefined), if deleteIconCssClass && deleteIconImage undefined then slick-groupby-remove-image class will be added
   *    deleteIconImage:     a url to the delete button image (default undefined)
   *    groupIconCssClass:   an extra CSS class to add to the grouping field hint  (default undefined)
   *    groupIconImage:      a url to the grouping field hint image (default undefined)
   *    dropPlaceHolderText:      option to specify set own placeholder note text
   *

   */

  function DraggableGrouping(options) {
    var _grid;
    var _gridUid;
    var _gridColumns;
    var _dataView;
    var dropbox;
    var dropboxPlaceholder;
    var groupToggler;
    var _self = this;
    var _defaults = {
    };
    var onGroupChanged = new Slick.Event();

    /**
     * Initialize plugin.
     */
    function init(grid) {
      options = $.extend(true, {}, _defaults, options);
      _grid = grid;
      _gridUid = _grid.getUID();
      _gridColumns =  _grid.getColumns();
      _dataView = _grid.getData();

      dropbox = $(_grid.getPreHeaderPanel());
      var dropPlaceHolderText = options.dropPlaceHolderText || 'Drop a column header here to group by the column';
      dropbox.html("
" + dropPlaceHolderText + "

");

      dropboxPlaceholder = dropbox.find(".slick-placeholder");
      groupToggler = dropbox.find(".slick-group-toggle-all");
      setupColumnDropbox();

      _grid.onHeaderCellRendered.subscribe(function (e, args) {
        var column = args.column;
        var node = args.node;
        if (!$.isEmptyObject(column.grouping)) {
          var groupableIcon = $("");
          if(options.groupIconCssClass) groupableIcon.addClass(options.groupIconCssClass)
          if(options.groupIconImage) groupableIcon.css("background", "url(" + options.groupIconImage + ") no-repeat center center");
          $(node).css('cursor', 'pointer').append(groupableIcon);
        }
      })

      for (var i = 0; i < _gridColumns.length; i++) {
        var columnId = _gridColumns[i].field;
        _grid.updateColumnHeader(columnId);
      }

    }

    function setupColumnReorder(grid, $headers, headerColumnWidthDiff, setColumns, setupColumnResize, columns, getColumnIndex, uid, trigger) {
      $headers.filter(":ui-sortable").sortable("destroy");
      var $headerDraggableGroupBy = $(grid.getPreHeaderPanel());
        $headers.sortable({
          distance: 3,
          cursor: "default",
          tolerance: "intersection",
          helper: "clone",
          placeholder: "slick-sortable-placeholder ui-state-default slick-header-column",
          forcePlaceholderSize: true,
          appendTo: "body",
          start: function(e, ui) {
            $(ui.helper).addClass("slick-header-column-active");
            $headerDraggableGroupBy.find(".slick-placeholder").show();
            $headerDraggableGroupBy.find(".slick-dropped-grouping").hide();
          },
          beforeStop: function(e, ui) {
            $(ui.helper).removeClass("slick-header-column-active");
            var hasDroppedColumn = $headerDraggableGroupBy.find(".slick-dropped-grouping").length;
            if(hasDroppedColumn > 0){
              $headerDraggableGroupBy.find(".slick-placeholder").hide();
              $headerDraggableGroupBy.find(".slick-dropped-grouping").show();
            }
          },
          stop: function(e) {
            if (!grid.getEditorLock().commitCurrentEdit()) {
              $(this).sortable("cancel");
              return;
            }
            var reorderedIds = $headers.sortable("toArray");
            var reorderedColumns = [];
            for (var i = 0; i < reorderedIds.length; i++) {
              reorderedColumns.push(columns[getColumnIndex(reorderedIds[i].replace(uid, ""))]);
            }
            setColumns(reorderedColumns);
            trigger(grid.onColumnsReordered, {
              grid: grid
            });
            e.stopPropagation();
            setupColumnResize();
          }
        });
    }

    /**
     * Destroy plugin.
     */
    function destroy() {
      onGroupChanged.unsubscribe();
    }

    function setColumns(col) {
      _gridColumns = col;
    }

    var emptyDropbox;

    function setupColumnDropbox() {
      dropbox.droppable({
        activeClass: "ui-state-default",
        hoverClass: "ui-state-hover",
        accept: ":not(.ui-sortable-helper)",
        deactivate: function(event, ui) {
          dropbox.removeClass("slick-header-column-denied");
        },
        drop: function(event, ui) {
          handleGroupByDrop(this, ui.draggable);
        },
        over: function(event, ui) {
          var id = (ui.draggable).attr('id').replace(_gridUid, "");
          _gridColumns.forEach(function(e, i, a) {
            if (e.id == id) {
              if (e.grouping == null) {
                dropbox.addClass("slick-header-column-denied");
              }
            }
          });
        }
      });
      dropbox.sortable({
        items: "div.slick-dropped-grouping",
        cursor: "default",
        tolerance: "pointer",
        helper: "clone",
        update: function(event, ui) {
          var sortArray = $(this).sortable('toArray', {
              attribute: 'data-id'
            }),
            newGroupingOrder = [];
          for (var i = 0, l = sortArray.length; i < l; i++) {
            for (var a = 0, b = columnsGroupBy.length; a < b; a++) {
              if (columnsGroupBy[a].id == sortArray[i]) {
                newGroupingOrder.push(columnsGroupBy[a]);
                break;
              }
            }
          }
          columnsGroupBy = newGroupingOrder;
          updateGroupBy();
        }
      });
      emptyDropbox = dropbox.html();

      groupToggler.on('click', function(e) {
        if (this.classList.contains('collapsed')) {
          this.classList.remove('collapsed');
          this.classList.add('expanded');
          _dataView.expandAllGroups();
        } else {
          this.classList.add('collapsed');
          this.classList.remove('expanded');
          _dataView.collapseAllGroups();
        }
      });
    }

    var columnsGroupBy = [];
    var groupBySorters = [];

    function handleGroupByDrop(container, column) {
      var columnid = column.attr('id').replace(_gridUid, "");
      var columnAllowed = true;
      columnsGroupBy.forEach(function(e, i, a) {
        if (e.id == columnid) {
          columnAllowed = false;
        }
      });
      if (columnAllowed) {
        _gridColumns.forEach(function(e, i, a) {
          if (e.id == columnid) {
            if (e.grouping != null && !$.isEmptyObject(e.grouping)) {
              var entry = $("
");
              var groupText = $("
" + column.text() + "
")
              groupText.appendTo(entry);
              var groupRemoveIcon = $("

")
              if(options.deleteIconCssClass) groupRemoveIcon.addClass(options.deleteIconCssClass);
              if(options.deleteIconImage) groupRemoveIcon.css("background", "url(" + options.deleteIconImage + ") no-repeat center right");
              if(!options.deleteIconCssClass && !options.deleteIconImage) groupRemoveIcon.addClass('slick-groupby-remove-image');
              groupRemoveIcon.appendTo(entry);

              $("
").appendTo(entry);
              entry.appendTo(container);
              addColumnGroupBy(e, column, container, entry);
              addGroupByRemoveClickHandler(e.id, container, column, entry);
            }
          }
        });
        groupToggler.css('display', 'block');
      }
    }

    function addColumnGroupBy(column) {
      columnsGroupBy.push(column);
      updateGroupBy();
    }

    function addGroupByRemoveClickHandler(id, container, column, entry) {
      var text = entry;
      $("#" + _gridUid + id + "_entry >.slick-groupby-remove").on('click', function() {
        $(this).off('click');
        removeGroupBy(id, column, text);
      });
    }

    function setDroppedGroups(groupingInfo) {
      groupingInfos = (groupingInfo instanceof Array) ? groupingInfo : [groupingInfo];
      dropboxPlaceholder.hide()
      for (var i = 0; i < groupingInfos.length; i++) {
        var column = $(_grid.getHeaderColumn(groupingInfos[i]));
        handleGroupByDrop(dropbox, column);
      }
    }
    function clearDroppedGroups() {
      columnsGroupBy = [];
      updateGroupBy();
      onGroupChanged.notify({ groupColumns: []})
      dropbox.find(".slick-dropped-grouping").remove();
      groupToggler.css("display", "none");
      dropboxPlaceholder.show()
    }

    function removeFromArray(arr) {
      var what, a = arguments,
        L = a.length,
        ax;
      while (L > 1 && arr.length) {
        what = a[--L];
        while ((ax = arr.indexOf(what)) != -1) {
          arr.splice(ax, 1);
        }
      }
      return arr;
    }

    function removeGroupBy(id, column, entry) {
      entry.remove();
      var groupby = [];
      _gridColumns.forEach(function(e, i, a) {
        groupby[e.id] = e;
      });
      removeFromArray(columnsGroupBy, groupby[id]);
      if(columnsGroupBy.length == 0){
        dropboxPlaceholder.show();
      }
      updateGroupBy();
    }

    function updateGroupBy() {
      if (columnsGroupBy.length == 0) {
        _dataView.setGrouping([]);
        onGroupChanged.notify({ groupColumns: [] });
        return;
      }
      var groupingArray = [];
      columnsGroupBy.forEach(function(element, index, array) {
        groupingArray.push(element.grouping);
      });
      _dataView.setGrouping(groupingArray);
      /*
      collapseAllGroups();
      */
      onGroupChanged.notify({ groupColumns: groupingArray})
    }

    // Public API
    $.extend(this, {
      "init": init,
      "destroy": destroy,
      "onGroupChanged": onGroupChanged,
      "setDroppedGroups": setDroppedGroups,
      "clearDroppedGroups": clearDroppedGroups,
      "getSetupColumnReorder": setupColumnReorder,
    });
  }
})(jQuery);
<|endoftext|>


<commit_before>/*!
 * jQuery Panelize - v0.8.2 - 2013-11-01
 * Image navigation with image maps
 *
 * (c) 2013 R.E. Warner @belovedleader
 * MIT Licensed.
 *
 * http://russellbits.github.io/panelize
 * http://github.com/russellbits/panelize
*/

jQuery.fn.panelize = function( options ) {

	var defaults = {
		container: this, // this should be used as opposed to explicit jquery references
		fullImageStart: true,
		panelViewerID : '#panelViewer',
		showNextBtnID : '#nextPanelBtn',
		showPrevBtnID : '#prevPanelBtn',
		resetBtnID: '#resetBtn'
	};

	var settings = $.extend( {}, defaults, options );

	var panels = {
		panelIndex: 0,
		panel: [],
		viewerWidth: this.width(),
		viewerHeight: this.height()
	};

	function Panel(x1, y1, x2, y2) {
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
		this.width = this.x2 - this.x1;
		this.height = this.y2 - this.y1;
	}

	// Intialize the panels in the comic
	// Assign area tag coordinates to the panels object (left,top,right,bottom)
	$(this).find('area').each(function(i) {
		if($(this).attr("target")!=null||$(this).attr("target")=="") {}
		else {
			var coords = $(this).attr('coords');
			var coordsStrArray = coords.split(',');
			panels.panel.push(new Panel(
				coordsStrArray[0],
				coordsStrArray[1],
				coordsStrArray[2],
				coordsStrArray[3]
			));
		}
	});

	var comic = $(settings.panelViewerID).find('img:first');

	/**
	* Start with full page option
	* 	The full scaled page will show, unless the user opts not to,
	* 	in which case, the first panel will zoom and show
	**/
	if(settings.fullImageStart) {
		var xOffset = 0;
		var yOffset = 0;

		// Add additional coordinates to return to full image
		panels.panel.unshift(new Panel(
			0,
			0,
			comic.width(),
			comic.height()
		));

		console.log('Total original width and height: '+comic.width()+', '+comic.height());

		if(comic.width() > comic.height()) {
			scaleFactor = panels.viewerWidth/comic.width();
			yOffset = Math.floor(((panels.viewerHeight-(comic.height()*scaleFactor))/2));
		} else {
			scaleFactor = panels.viewerHeight/comic.height();
			xOffset = Math.floor(((panels.viewerWidth-(comic.width()*scaleFactor))/2));
		}
		console.log("Scaling to full scale image by "+scaleFactor);

		comic.css({transformOrigin:'0px 0px'})
			.animate({
				left:xOffset,
				top:yOffset,
				'-webkit-transform': 'scale('+scalFactor+')',
				'-moz-transform': 'scale('+scalFactor+')',
				'-o-transform': 'scale('+scalFactor+')'});

		panels.panelIndex = 0;

	} else {
		panels.panelIndex = -1;
		transformPanel();
	}

	/**
	* MAIN TRANSFORM FUNCTION
	**/
	function transformPanel(dir) {
		// If previous,
		if(dir=='prev') {
			panels.panelIndex -= 1;
		} else {
			panels.panelIndex += 1;
		}

		// Reset to first panel when index hits maximum
		if(panels.panelIndex == panels.panel.length || panels.panelIndex < 0) {
			panels.panelIndex = 0;
		}

		console.log('Current index: '+panels.panelIndex);

		// Assign local variables
		var panelTop = panels.panel[panels.panelIndex].y1;
		var panelLeft = panels.panel[panels.panelIndex].x1;
		var panelWidth = panels.panel[panels.panelIndex].width;
		var panelHeight = panels.panel[panels.panelIndex].height;
		var panelBottom = panels.panel[panels.panelIndex].y2;
		var panelRight = panels.panel[panels.panelIndex].x2;
		var offsetIsX;
		var yOffset = 0;
		var xOffset = 0;
		var portraitMode = true;

		// Check if we are dealing with a portrait or landscape viewer
		if(panels.viewerWidth > panels.viewerHeight) {
			portraitMode = true;
		} else {
			portraitMode = false;
		}

		if(panelWidth > panelHeight || portraitMode==false) {
			var usingWidthAsMax = true;
			scaleFactor = panels.viewerWidth/panelWidth;
			offsetIsX = true;
		} else {
			var usingWidthAsMax = false;
			scaleFactor = panels.viewerHeight/panelHeight;
			offsetIsX = false;
		}

		var scaledPanelHeight = Math.floor(panelHeight*scaleFactor);
		var scaledPanelWdith = Math.floor(panelWidth*scaleFactor);

		// need to divide the offest by the scalefactor?
		if(offsetIsX) {
			yOffset = Math.floor((panels.viewerHeight-scaledPanelHeight)/2);
		} else {
			xOffset = Math.floor((panels.viewerWidth-scaledPanelWdith)/2);
		}

		// Perform the actual transformation
		var Xmove = -panelLeft+xOffset;
		var Ymove = -panelTop+yOffset;

		comic.css({transformOrigin:'0px 0px'})
			.animate({left:Xmove*scaleFactor,top:Ymove*scaleFactor,scale:'scaleFactor,scaleFactor'});

	}

	/**
	* Interactive functions (UI)
	**/
	$(settings.showNextBtnID).click(function(event) {
		console.log('Next button activated');
		event.preventDefault();
		transformPanel('next');
	});

	$(settings.showPrevBtnID).click(function(event) {
		console.log('Previous button activated');
		event.preventDefault();
		transformPanel('prev');
	});

};<commit_msg>scalFactor is not how the variable is spelled. Sigh<commit_after>/*!
 * jQuery Panelize - v0.8.2 - 2013-11-01
 * Image navigation with image maps
 *
 * (c) 2013 R.E. Warner @belovedleader
 * MIT Licensed.
 *
 * http://russellbits.github.io/panelize
 * http://github.com/russellbits/panelize
*/

jQuery.fn.panelize = function( options ) {

	var defaults = {
		container: this, // this should be used as opposed to explicit jquery references
		fullImageStart: true,
		panelViewerID : '#panelViewer',
		showNextBtnID : '#nextPanelBtn',
		showPrevBtnID : '#prevPanelBtn',
		resetBtnID: '#resetBtn'
	};

	var settings = $.extend( {}, defaults, options );

	var panels = {
		panelIndex: 0,
		panel: [],
		viewerWidth: this.width(),
		viewerHeight: this.height()
	};

	function Panel(x1, y1, x2, y2) {
		this.x1 = x1;
		this.y1 = y1;
		this.x2 = x2;
		this.y2 = y2;
		this.width = this.x2 - this.x1;
		this.height = this.y2 - this.y1;
	}

	// Intialize the panels in the comic
	// Assign area tag coordinates to the panels object (left,top,right,bottom)
	$(this).find('area').each(function(i) {
		if($(this).attr("target")!=null||$(this).attr("target")=="") {}
		else {
			var coords = $(this).attr('coords');
			var coordsStrArray = coords.split(',');
			panels.panel.push(new Panel(
				coordsStrArray[0],
				coordsStrArray[1],
				coordsStrArray[2],
				coordsStrArray[3]
			));
		}
	});

	var comic = $(settings.panelViewerID).find('img:first');

	/**
	* Start with full page option
	* 	The full scaled page will show, unless the user opts not to,
	* 	in which case, the first panel will zoom and show
	**/
	if(settings.fullImageStart) {
		var xOffset = 0;
		var yOffset = 0;

		// Add additional coordinates to return to full image
		panels.panel.unshift(new Panel(
			0,
			0,
			comic.width(),
			comic.height()
		));

		console.log('Total original width and height: '+comic.width()+', '+comic.height());

		if(comic.width() > comic.height()) {
			scaleFactor = panels.viewerWidth/comic.width();
			yOffset = Math.floor(((panels.viewerHeight-(comic.height()*scaleFactor))/2));
		} else {
			scaleFactor = panels.viewerHeight/comic.height();
			xOffset = Math.floor(((panels.viewerWidth-(comic.width()*scaleFactor))/2));
		}
		console.log("Scaling to full scale image by "+scaleFactor);

		comic.css({transformOrigin:'0px 0px'})
			.animate({
				left:xOffset,
				top:yOffset,
				'-webkit-transform': 'scale('+scaleFactor+')',
				'-moz-transform': 'scale('+scaleFactor+')',
				'-o-transform': 'scale('+scaleFactor+')'});

		panels.panelIndex = 0;

	} else {
		panels.panelIndex = -1;
		transformPanel();
	}

	/**
	* MAIN TRANSFORM FUNCTION
	**/
	function transformPanel(dir) {
		// If previous,
		if(dir=='prev') {
			panels.panelIndex -= 1;
		} else {
			panels.panelIndex += 1;
		}

		// Reset to first panel when index hits maximum
		if(panels.panelIndex == panels.panel.length || panels.panelIndex < 0) {
			panels.panelIndex = 0;
		}

		console.log('Current index: '+panels.panelIndex);

		// Assign local variables
		var panelTop = panels.panel[panels.panelIndex].y1;
		var panelLeft = panels.panel[panels.panelIndex].x1;
		var panelWidth = panels.panel[panels.panelIndex].width;
		var panelHeight = panels.panel[panels.panelIndex].height;
		var panelBottom = panels.panel[panels.panelIndex].y2;
		var panelRight = panels.panel[panels.panelIndex].x2;
		var offsetIsX;
		var yOffset = 0;
		var xOffset = 0;
		var portraitMode = true;

		// Check if we are dealing with a portrait or landscape viewer
		if(panels.viewerWidth > panels.viewerHeight) {
			portraitMode = true;
		} else {
			portraitMode = false;
		}

		if(panelWidth > panelHeight || portraitMode==false) {
			var usingWidthAsMax = true;
			scaleFactor = panels.viewerWidth/panelWidth;
			offsetIsX = true;
		} else {
			var usingWidthAsMax = false;
			scaleFactor = panels.viewerHeight/panelHeight;
			offsetIsX = false;
		}

		var scaledPanelHeight = Math.floor(panelHeight*scaleFactor);
		var scaledPanelWdith = Math.floor(panelWidth*scaleFactor);

		// need to divide the offest by the scalefactor?
		if(offsetIsX) {
			yOffset = Math.floor((panels.viewerHeight-scaledPanelHeight)/2);
		} else {
			xOffset = Math.floor((panels.viewerWidth-scaledPanelWdith)/2);
		}

		// Perform the actual transformation
		var Xmove = -panelLeft+xOffset;
		var Ymove = -panelTop+yOffset;

		comic.css({transformOrigin:'0px 0px'})
			.animate({left:Xmove*scaleFactor,top:Ymove*scaleFactor,scale:'scaleFactor,scaleFactor'});

	}

	/**
	* Interactive functions (UI)
	**/
	$(settings.showNextBtnID).click(function(event) {
		console.log('Next button activated');
		event.preventDefault();
		transformPanel('next');
	});

	$(settings.showPrevBtnID).click(function(event) {
		console.log('Previous button activated');
		event.preventDefault();
		transformPanel('prev');
	});

};<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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
 *
 * http://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.
*/
(function() {
    'use strict';
    /* global myApp */
    myApp.factory('AppsService', ['$q', '$location', 'ResourcesLoader', 'INSTALL_DIRECTORY', 'APPS_JSON', 'AppHarnessUI', function($q, $location, ResourcesLoader, INSTALL_DIRECTORY, APPS_JSON, AppHarnessUI) {
        // Map of type -> installer.
        var _installerFactories = Object.create(null);
        // Array of installer objects.
        var _installers = null;
        // The app that is currently running.
        var activeInstaller = null;

        function readAppsJson() {
            var deferred = $q.defer();
            ResourcesLoader.readJSONFileContents(APPS_JSON)
            .then(function(result) {
                if (result['fileVersion'] !== 1) {
                    console.warn('Ignoring old version of apps.json');
                    result = {};
                }
                deferred.resolve(result);
            }, function() {
                // Error means first run.
                deferred.resolve({});
            });
            return deferred.promise;
        }

        function initHandlers() {
            if (_installers) {
                return $q.when();
            }

            return readAppsJson()
            .then(function(json) {
                var appList = json['appList'] || [];
                _installers = [];
                var i = -1;
                return $q.when()
                .then(function next() {
                    var entry = appList[++i];
                    if (!entry) {
                        return;
                    }
                    var Ctor = _installerFactories[entry['appType']];
                    return new Ctor().initFromJson(entry)
                    .then(function(app) {
                        _installers.push(app);
                        return next();
                    }, next);
                });
            });
        }

        function createAppsJson() {
            var appsJson = {
                'fileVersion': 1,
                'appList': []
            };
            for (var i = 0; i < _installers.length; ++i) {
                var installer = _installers[i];
                appsJson.appList.push(installer.toDiskJson());
            }
            return appsJson;
        }

        function writeAppsJson() {
            if (AppsService.onAppListChange) {
                AppsService.onAppListChange();
            }
            var appsJson = createAppsJson();
            var stringContents = JSON.stringify(appsJson, null, 4);
            return ResourcesLoader.writeFileContents(APPS_JSON, stringContents);
        }

        var AppsService = {
            // return promise with the array of apps
            getAppList : function() {
                return initHandlers()
                .then(function() {
                    return _installers.slice();
                });
            },

            getActiveApp: function() {
                return activeInstaller;
            },

            getAppListAsJson : function() {
                return createAppsJson();
            },

            // If no appId, then return the first app.
            // If appId and appType, then create it if it doesn't exist.
            // Else: return null.
            getAppById : function(appId, /* optional */ appType) {
                return initHandlers()
                .then(function() {
                    var matches = _installers;
                    if (appId) {
                        matches = _installers.filter(function(x) {
                            return x.appId == appId;
                        });
                    }
                    if (matches.length > 0) {
                        return matches[0];
                    }
                    if (appType) {
                        return AppsService.addApp(appType, appId);
                    }
                    return null;
                });
            },

            quitApp : function() {
                if (activeInstaller) {
                    activeInstaller.unlaunch();
                    activeInstaller = null;
                    return AppHarnessUI.destroy();
                }
                return $q.when();
            },

            launchApp : function(installer) {
                // Determine whether we're relaunching the same app as is already active.
                var activeAppId = activeInstaller && activeInstaller.appId;
                var newAppId = installer && installer.appId;
                var relaunch = activeAppId && newAppId && activeAppId === newAppId;

                return $q.when()
                .then(function() {
                    // If we're relaunching the active app, move on.
                    // Otherwise, quit the active app.
                    // TODO(maxw): Determine whether we actually ever need to quit the app.
                    if (relaunch) {
                        return $q.when();
                    } else {
                        return AppsService.quitApp();
                    }
                }).then(function() {
                    activeInstaller = installer;
                    return installer.launch();
                }).then(function(launchUrl) {
                    return installer.getPluginMetadata()
                    .then(function(pluginMetadata) {
                        $location.path('/inappmenu');
                        // If we're relaunching the active app, just reload the existing webview.
                        // Otherwise, create a new one.
                        // TODO(maxw): Use the existing webview all the time.
                        if (relaunch) {
                            return AppHarnessUI.reload(launchUrl, pluginMetadata, 'system');
                        } else {
                            return AppHarnessUI.create(launchUrl, pluginMetadata);
                        }
                    }).then(function() {
                        if (AppsService.onAppListChange) {
                            AppsService.onAppListChange();
                        }
                    });
                });
            },

            addApp : function(appType, /* optional */ appId) {
                var installPath = INSTALL_DIRECTORY + 'app' + Math.floor(Math.random() * 0xFFFFFFFF).toString(36) + '/';
                return initHandlers().then(function() {
                    var Ctor = _installerFactories[appType];
                    return new Ctor().init(installPath, appId);
                }).then(function(installer) {
                    _installers.push(installer);
                    return writeAppsJson()
                    .then(function() {
                        return installer;
                    });
                });
            },

            uninstallAllApps : function() {
                return this.quitApp()
                .then(function() {
                    var deletePromises = [];
                    for (var i = 0; i < _installers.length; ++i) {
                        deletePromises.push(AppsService.uninstallApp(_installers[i]));
                    }
                    return $q.all(deletePromises);
                });
            },

            uninstallApp : function(installer) {
                var ret = $q.when();
                if (installer == activeInstaller) {
                    ret = this.quitApp();
                }
                return ret.then(function() {
                    return installer.deleteFiles();
                }).then(function() {
                    _installers.splice(_installers.indexOf(installer), 1);
                    return writeAppsJson();
                });
            },

            triggerAppListChange: function() {
                return writeAppsJson();
            },

            registerInstallerFactory : function(installerFactory) {
                 _installerFactories[installerFactory.type] = installerFactory;
            },

            onAppListChange: null
        };
        return AppsService;
    }]);
})();
<commit_msg>Allow installer.getPluginMetadata() to return a value instead of a promise<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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
 *
 * http://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.
*/
(function() {
    'use strict';
    /* global myApp */
    myApp.factory('AppsService', ['$q', '$location', 'ResourcesLoader', 'INSTALL_DIRECTORY', 'APPS_JSON', 'AppHarnessUI', function($q, $location, ResourcesLoader, INSTALL_DIRECTORY, APPS_JSON, AppHarnessUI) {
        // Map of type -> installer.
        var _installerFactories = Object.create(null);
        // Array of installer objects.
        var _installers = null;
        // The app that is currently running.
        var activeInstaller = null;

        function readAppsJson() {
            var deferred = $q.defer();
            ResourcesLoader.readJSONFileContents(APPS_JSON)
            .then(function(result) {
                if (result['fileVersion'] !== 1) {
                    console.warn('Ignoring old version of apps.json');
                    result = {};
                }
                deferred.resolve(result);
            }, function() {
                // Error means first run.
                deferred.resolve({});
            });
            return deferred.promise;
        }

        function initHandlers() {
            if (_installers) {
                return $q.when();
            }

            return readAppsJson()
            .then(function(json) {
                var appList = json['appList'] || [];
                _installers = [];
                var i = -1;
                return $q.when()
                .then(function next() {
                    var entry = appList[++i];
                    if (!entry) {
                        return;
                    }
                    var Ctor = _installerFactories[entry['appType']];
                    return new Ctor().initFromJson(entry)
                    .then(function(app) {
                        _installers.push(app);
                        return next();
                    }, next);
                });
            });
        }

        function createAppsJson() {
            var appsJson = {
                'fileVersion': 1,
                'appList': []
            };
            for (var i = 0; i < _installers.length; ++i) {
                var installer = _installers[i];
                appsJson.appList.push(installer.toDiskJson());
            }
            return appsJson;
        }

        function writeAppsJson() {
            if (AppsService.onAppListChange) {
                AppsService.onAppListChange();
            }
            var appsJson = createAppsJson();
            var stringContents = JSON.stringify(appsJson, null, 4);
            return ResourcesLoader.writeFileContents(APPS_JSON, stringContents);
        }

        var AppsService = {
            // return promise with the array of apps
            getAppList : function() {
                return initHandlers()
                .then(function() {
                    return _installers.slice();
                });
            },

            getActiveApp: function() {
                return activeInstaller;
            },

            getAppListAsJson : function() {
                return createAppsJson();
            },

            // If no appId, then return the first app.
            // If appId and appType, then create it if it doesn't exist.
            // Else: return null.
            getAppById : function(appId, /* optional */ appType) {
                return initHandlers()
                .then(function() {
                    var matches = _installers;
                    if (appId) {
                        matches = _installers.filter(function(x) {
                            return x.appId == appId;
                        });
                    }
                    if (matches.length > 0) {
                        return matches[0];
                    }
                    if (appType) {
                        return AppsService.addApp(appType, appId);
                    }
                    return null;
                });
            },

            quitApp : function() {
                if (activeInstaller) {
                    activeInstaller.unlaunch();
                    activeInstaller = null;
                    return AppHarnessUI.destroy();
                }
                return $q.when();
            },

            launchApp : function(installer) {
                // Determine whether we're relaunching the same app as is already active.
                var activeAppId = activeInstaller && activeInstaller.appId;
                var newAppId = installer && installer.appId;
                var relaunch = activeAppId && newAppId && activeAppId === newAppId;

                return $q.when()
                .then(function() {
                    // If we're relaunching the active app, move on.
                    // Otherwise, quit the active app.
                    // TODO(maxw): Determine whether we actually ever need to quit the app.
                    if (relaunch) {
                        return $q.when();
                    } else {
                        return AppsService.quitApp();
                    }
                }).then(function() {
                    activeInstaller = installer;
                    return installer.launch();
                }).then(function(launchUrl) {
                    return $q.when(installer.getPluginMetadata())
                    .then(function(pluginMetadata) {
                        $location.path('/inappmenu');
                        // If we're relaunching the active app, just reload the existing webview.
                        // Otherwise, create a new one.
                        // TODO(maxw): Use the existing webview all the time.
                        if (relaunch) {
                            return AppHarnessUI.reload(launchUrl, pluginMetadata, 'system');
                        } else {
                            return AppHarnessUI.create(launchUrl, pluginMetadata);
                        }
                    }).then(function() {
                        if (AppsService.onAppListChange) {
                            AppsService.onAppListChange();
                        }
                    });
                });
            },

            addApp : function(appType, /* optional */ appId) {
                var installPath = INSTALL_DIRECTORY + 'app' + Math.floor(Math.random() * 0xFFFFFFFF).toString(36) + '/';
                return initHandlers().then(function() {
                    var Ctor = _installerFactories[appType];
                    return new Ctor().init(installPath, appId);
                }).then(function(installer) {
                    _installers.push(installer);
                    return writeAppsJson()
                    .then(function() {
                        return installer;
                    });
                });
            },

            uninstallAllApps : function() {
                return this.quitApp()
                .then(function() {
                    var deletePromises = [];
                    for (var i = 0; i < _installers.length; ++i) {
                        deletePromises.push(AppsService.uninstallApp(_installers[i]));
                    }
                    return $q.all(deletePromises);
                });
            },

            uninstallApp : function(installer) {
                var ret = $q.when();
                if (installer == activeInstaller) {
                    ret = this.quitApp();
                }
                return ret.then(function() {
                    return installer.deleteFiles();
                }).then(function() {
                    _installers.splice(_installers.indexOf(installer), 1);
                    return writeAppsJson();
                });
            },

            triggerAppListChange: function() {
                return writeAppsJson();
            },

            registerInstallerFactory : function(installerFactory) {
                 _installerFactories[installerFactory.type] = installerFactory;
            },

            onAppListChange: null
        };
        return AppsService;
    }]);
})();
<|endoftext|>


<commit_before>/*
Plugin: jQuery Parallax
Version 1.0.0
Author: Ionuț Staicu
License: MIT
*/

(function( $, document ){
	if (!Object.create) { Object.create = function (o) { if (arguments.length > 1) { throw new Error('Object.create implementation only accepts the first parameter.'); } function F() {} F.prototype = o; return new F(); }; }

	var Parallax = {
		init: function( el, options ){
			this.el = $( el );
			this.win = $( window );

			this.options = options;

			this.appendBackground();

			this.win.on( 'resize', $.proxy( this.reInitialize, this ) );
			this.win.on( 'scroll', $.proxy( this.scroll, this ) );

			$( window ).on('re-parallax', $.proxy( this.reInitialize, this ) );
			$( window ).trigger('re-parallax');
		},

		reInitialize: function(){
			this.winHeight  = this.win.height();
			this.initialTop = this.el.offset().top;
			this.scroll();
		},

		appendBackground: function(){
			this.divBG = $('<div />');

			if( this.options.defaultStyling ){
				this.divBG.css({
					position       : 'absolute',
					background     : 'no-repeat center center fixed',
					backgroundSize : 'cover',
					width          : '100%',
					bottom         : 0,
					left           : 0,
					top            : 0,
					zIndex         : -1,
				});

				this.el.css( 'position', 'relative' );
			}

			this.divBG.css({
				backgroundImage: 'url(' + this.el.attr('data-image') + ')'
			});

			this.el.append( this.divBG );
		},

		scroll: function(){
			var scrollTop = this.win.scrollTop();
			var currentTop = this.el.offset().top;
			var height = this.el.outerHeight( true );
			var newYPos = Math.round( ( this.initialTop - scrollTop ) * this.options.speed );

			newYPos += 'px';

			if ( currentTop + height < scrollTop || currentTop > scrollTop + this.winHeight) {
				return;
			}

			this.divBG.css('backgroundPosition', [ '50%', newYPos ].join(' ') );
		},
	};

	$.fn.parallax = function( options ) {
		options = options || {};

		options = $.extend({
			speed         : 0.5,
			defaultStyling: true
		}, options );

		return this.each(function(){
			var obj = Object.create( Parallax );
			obj.init( this, options );
		});
	};
})( jQuery, document );

<commit_msg>Improved options handling<commit_after>/*
Plugin: jQuery Parallax
Version 1.0.0
Author: Ionuț Staicu
License: MIT
*/

(function( $, document ){
	if (!Object.create) { Object.create = function (o) { if (arguments.length > 1) { throw new Error('Object.create implementation only accepts the first parameter.'); } function F() {} F.prototype = o; return new F(); }; }

	var Parallax = {
		init: function( el, options ){
			this.el = $( el );
			this.win = $( window );

			this.options = options;

			this.appendBackground();

			this.win.on( 'resize', $.proxy( this.reInitialize, this ) );
			this.win.on( 'scroll', $.proxy( this.scroll, this ) );

			$( window ).on('re-parallax', $.proxy( this.reInitialize, this ) );
			$( window ).trigger('re-parallax');
		},

		reInitialize: function(){
			this.winHeight  = this.win.height();
			this.initialTop = this.el.offset().top;
			this.scroll();
		},

		appendBackground: function(){
			this.divBG = $('<div />');

			if( this.options.defaultStyling ){
				this.divBG.css({
					position       : 'absolute',
					background     : 'no-repeat center center fixed',
					backgroundSize : 'cover',
					width          : '100%',
					bottom         : 0,
					left           : 0,
					top            : 0,
					zIndex         : -1,
				});

				this.el.css( 'position', 'relative' );
			}

			this.divBG.css({
				backgroundImage: 'url(' + this.el.attr('data-image') + ')'
			});

			this.el.append( this.divBG );
		},

		scroll: function(){
			var scrollTop = this.win.scrollTop();
			var currentTop = this.el.offset().top;
			var height = this.el.outerHeight( true );
			var newYPos = Math.round( ( this.initialTop - scrollTop ) * this.options.speed );

			newYPos += 'px';

			if ( currentTop + height < scrollTop || currentTop > scrollTop + this.winHeight) {
				return;
			}

			this.divBG.css('backgroundPosition', [ '50%', newYPos ].join(' ') );
		},
	};

	$.fn.parallax = function( options ) {
		options = options || {};

		options = $.extend({
			speed         : 0.5,
			defaultStyling: true
		}, options );

		return this.each(function(){
			var obj = Object.create( Parallax );
			var itemOptions = $.extend( {}, options, $( this ).data() );
			obj.init( this, itemOptions );
		});
	};
})( jQuery, document );<|endoftext|>