<commit_before>/*eslint-disable*/
/* global spawnPowers:true, players, totalTime, PowerUp, w2,
h2, countdown, colorPlayers, adjustScreen */
/*eslint-enable*/
var MPNormal = function (nPlayers, game) {
  this.game = game
  this.nPlayers = nPlayers
  this.spawnPowers = true
  this.highScore = 0
  this.gridded = true
}

MPNormal.prototype = {
  create: function (manager) {
    this.crowned = -1
    this.lastCrowned = -1
    this.manager = manager
    this.highScore = 0
    spawnPowers = true
  },

  update: function () {
    if (this.crowned !== -1) {
      players[this.crowned].addCrown()
    }
    if (!countdown) {
      if (this.manager.gameTime >= (totalTime)) {
        this.manager.ui.timeCircle.scale.set((-1 / this.manager.gameTime) * (totalTime) + 1)
      } else {
        this.manager.endGame()
      }
    }

    var numberAlive = 0
    var playerAlive = -1
    for (var i = 0; i < players.length; i++) {
      if (!players[i].dead) {
        playerAlive = i
        numberAlive++
        if (numberAlive > 1) break
      }
    }
    if (numberAlive < 2) {
      this.lastCrowned = playerAlive
      this.manager.endGame()
    }
  },

  erasesTrail: function () {
    return true
  },

  collect: function (playerSprite, powerSprite, player) {
    player.growth = 60 * powerSprite.scale.x
    player.size += player.growth

    if (player.size > this.highScore) {
      this.highScore = player.size
      if (this.crowned > -1) {
        players[this.crowned].removeCrown()
      }
      this.lastCrowned = this.crowned
      this.crowned = player.id
    }
  },

  kill: function () {
    var alreadyDead = 0
    for (var i = 0; i < players.length; i++) {
      if (players[i].dead) {
        alreadyDead++
      }
    }

    var newMax = 0
    for (i = 0; i < players.length; i++) {
      if (players.length - alreadyDead === 1 && i !== this.id && !players[i].dead) {
        newMax = players[i].size
        this.crowned = i
      } else if (i !== this.id && players[i].size > newMax && !players[i].dead) {
        newMax = players[i].size
        this.crowned = i
      }
    }

    if (this.crowned !== -1 && players[this.crowned].dead) {
      this.crowned = -1
      this.highScore = 0
    }
  },

  createPower: function () {
    var powerup = new PowerUp(this.game, 'pointMP', this)
    powerup.create()
  },

  endGame: function (bottomY) {
    if (this.crowned === -1) {
      var tie = this.game.add.sprite(w2, h2 + 250, 'tie')
      tie.anchor.setTo(0.5, 0.5)
    } else {
      var winnerFill = this.game.add.sprite(w2 - 75, bottomY + 157, 'player' + players[this.crowned].id)
      winnerFill.scale.set(5)
      winnerFill.anchor.setTo(0.5, 0.5)

      var winnerLabel = this.game.add.sprite(w2, bottomY + 157, 'winner')
      winnerLabel.scale.set(1, 1)
      winnerLabel.anchor.setTo(0.5, 0.5)
      var textWinner = this.game.add.text(w2 + 50, bottomY + 160, String.fromCharCode(players[this.crowned].key), {
        font: '100px dosis',
        fill: colorPlayers[this.crowned],
        align: 'center'
      })
      textWinner.anchor.setTo(0.5, 0.5)
    }
  },

  setScreen: function () {
    adjustScreen(this.game)
  },

  getHighScore: function () {
    return this.highScore
  },

  setHighScore: function (score) {
    this.highScore = score
  }
}
<commit_msg>close #187<commit_after>/*eslint-disable*/
/* global spawnPowers:true, players, totalTime, PowerUp, w2,
h2, countdown, colorPlayers, adjustScreen */
/*eslint-enable*/
var MPNormal = function (nPlayers, game) {
  this.game = game
  this.nPlayers = nPlayers
  this.spawnPowers = true
  this.highScore = 0
  this.gridded = true
}

MPNormal.prototype = {
  create: function (manager) {
    this.crowned = -1
    this.lastCrowned = -1
    this.manager = manager
    this.highScore = 0
    spawnPowers = true
  },

  update: function () {
    if (this.crowned !== -1) {
      players[this.crowned].addCrown()
    }
    if (!countdown) {
      if (this.manager.gameTime >= (totalTime)) {
        this.manager.ui.timeCircle.scale.set((-1 / this.manager.gameTime) * (totalTime) + 1)
      } else {
        this.manager.endGame()
      }
    }

    var numberAlive = 0
    var playerAlive = -1
    for (var i = 0; i < players.length; i++) {
      if (!players[i].dead) {
        playerAlive = i
        numberAlive++
        if (numberAlive > 1) break
      }
    }
    if (numberAlive < 2) {
      this.lastCrowned = playerAlive
      this.manager.endGame()
    }
  },

  erasesTrail: function () {
    return true
  },

  collect: function (playerSprite, powerSprite, player) {
    player.growth = 60 * powerSprite.scale.x
    player.size += player.growth

    if (player.size > this.highScore) {
      this.highScore = player.size
      if (this.crowned > -1) {
        players[this.crowned].removeCrown()
      }
      this.lastCrowned = this.crowned
      this.crowned = player.id
    }
  },

  kill: function () {
    var alreadyDead = 0
    for (var i = 0; i < players.length; i++) {
      if (players[i].dead) {
        alreadyDead++
      }
    }

    var newMax = 0
    for (i = 0; i < players.length; i++) {
      if (players.length - alreadyDead === 1 && i !== this.id && !players[i].dead) {
        newMax = players[i].size
        this.crowned = i
      } else if (i !== this.id && players[i].size > newMax && !players[i].dead) {
        newMax = players[i].size
        this.crowned = i
      }
    }

    if (this.crowned !== -1 && players[this.crowned].dead) {
      this.crowned = -1
      this.highScore = 0
    }
  },

  createPower: function () {
    if (!countdown) {
      var powerup = new PowerUp(this.game, 'pointMP', this)
      powerup.create()
    }
  },

  endGame: function (bottomY) {
    if (this.crowned === -1) {
      var tie = this.game.add.sprite(w2, h2 + 250, 'tie')
      tie.anchor.setTo(0.5, 0.5)
    } else {
      var winnerFill = this.game.add.sprite(w2 - 75, bottomY + 157, 'player' + players[this.crowned].id)
      winnerFill.scale.set(5)
      winnerFill.anchor.setTo(0.5, 0.5)

      var winnerLabel = this.game.add.sprite(w2, bottomY + 157, 'winner')
      winnerLabel.scale.set(1, 1)
      winnerLabel.anchor.setTo(0.5, 0.5)
      var textWinner = this.game.add.text(w2 + 50, bottomY + 160, String.fromCharCode(players[this.crowned].key), {
        font: '100px dosis',
        fill: colorPlayers[this.crowned],
        align: 'center'
      })
      textWinner.anchor.setTo(0.5, 0.5)
    }
  },

  setScreen: function () {
    adjustScreen(this.game)
  },

  getHighScore: function () {
    return this.highScore
  },

  setHighScore: function (score) {
    this.highScore = score
  }
}
<|endoftext|>


<commit_before> //create a new Game instance
 //set the game dimensions and set the Phaser.AUTO (OpenGL or Canvas)
 var game = new Phaser.Game(640, 360, Phaser.AUTO);

//create a game state (this contains the logic of the game)
var GameState = {

	//assets are loaded in this function
	preload: function(){

        //load the images from the assets folder
        this.load.image('backgroundImageKey', 'assets/images/background.png');
        this.load.image('chickenImageKey', 'assets/images/chicken.png');
        this.load.image('horseImageKey', 'assets/images/horse.png');
        this.load.image('pigImageKey', 'assets/images/pig.png');
        this.load.image('sheepImageKey', 'assets/images/sheep.png');
        this.load.image('arrowImageKey', 'assets/images/arrow.png');

	},
	//after preloading create function is called
	create: function(){

        //to make the game responsive i.e. make it viewable on different types of devices
        //SHOW_ALL mode makes the game fit the screen
        this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;

        //to align the game in the center
        this.scale.pageAlignHorizontally = true;
        this.scale.pageAlignVertically = true;

        //this will create a sprite for the background
        this.background = this.game.add.sprite(0,0, 'backgroundImageKey');

        //this will create a sprite for the chicken
        this.chicken = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY, 'chickenImageKey');
        //by default the anchor point is top left corner of the image
        //inorder to change it we do it so with the following code
        this.chicken.anchor.setTo(0.5, 0.5);//takes two arguments for X and Y, if both X and Y values are same then one argument will do the job

        //left arrow (previous)
        this.leftArrow = this.game.add.sprite(this.game.world.centerX - 210, this.game.world.centerY - 50, 'arrowImageKey');
        this.leftArrow.anchor.setTo = (0.5, 0.5);
        this.leftArrow.scale.x = -1;//flip the right arrow to make the left arrow
        this.leftArrow.customParams = {direction: 1};

        //event: when left arrow is clicked
        this.leftArrow.inputEnabled = true;//enable input
        this.leftArrow.input.pixelPerfectClick = true;//this will the clickable area to shape of the sprite and not a regular rectangle
        this.leftArrow.events.onInputDown.add(this.changeAnimal, this);//add event when user clicks

        //right arrow (next)
        this.rightArrow = this.game.add.sprite(this.game.world.centerX + 210, this.game.world.centerY - 50, 'arrowImageKey');
        this.rightArrow.anchor.setTo = (0.5, 0.5);
        this.rightArrow.customParams = {direction: 1};

         //event: when right arrow is clicked
        this.rightArrow.inputEnabled = true;//enable input
        this.rightArrow.input.pixelPerfectClick = true;//this will the clickable area to shape of the sprite and not a regular rectangle
        this.rightArrow.events.onInputDown.add(this.changeAnimal, this);//add event when user clicks

	},
	//this function is called multiple times to handle the requests when game is live
	update: function(){

	},

    //changeAnimal function
    changeAnimal: function(sprite, event){
        console.log(sprite, event);
    }

};

//add state to the main game
game.state.add('GameState', GameState);

//to launch the game
game.state.start('GameState');<commit_msg>add event for the animal<commit_after> //create a new Game instance
 //set the game dimensions and set the Phaser.AUTO (OpenGL or Canvas)
 var game = new Phaser.Game(640, 360, Phaser.AUTO);

//create a game state (this contains the logic of the game)
var GameState = {

	//assets are loaded in this function
	preload: function(){

        //load the images from the assets folder
        this.load.image('backgroundImageKey', 'assets/images/background.png');
        this.load.image('chickenImageKey', 'assets/images/chicken.png');
        this.load.image('horseImageKey', 'assets/images/horse.png');
        this.load.image('pigImageKey', 'assets/images/pig.png');
        this.load.image('sheepImageKey', 'assets/images/sheep.png');
        this.load.image('arrowImageKey', 'assets/images/arrow.png');

	},
	//after preloading create function is called
	create: function(){

        //to make the game responsive i.e. make it viewable on different types of devices
        //SHOW_ALL mode makes the game fit the screen
        this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;

        //to align the game in the center
        this.scale.pageAlignHorizontally = true;
        this.scale.pageAlignVertically = true;

        //this will create a sprite for the background
        this.background = this.game.add.sprite(0,0, 'backgroundImageKey');

        //this will create a sprite for the chicken
        this.chicken = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY, 'chickenImageKey');
        //by default the anchor point is top left corner of the image
        //inorder to change it we do it so with the following code
        this.chicken.anchor.setTo(0.5, 0.5);//takes two arguments for X and Y, if both X and Y values are same then one argument will do the job

        //event: when user clicks on the animal
        this.chicken.inputEnabled = true;//enable input
        this.chicken.input.pixelPerfectClick = true;//this will the clickable area to shape of the sprite and not a regular rectangle
        this.chicken.events.onInputDown.add(this.animateAnimal, this);//add event when user clicks

        //left arrow (previous)
        this.leftArrow = this.game.add.sprite(this.game.world.centerX - 210, this.game.world.centerY - 50, 'arrowImageKey');
        this.leftArrow.anchor.setTo = (0.5, 0.5);
        this.leftArrow.scale.x = -1;//flip the right arrow to make the left arrow
        this.leftArrow.customParams = {direction: 1};

        //event: when left arrow is clicked
        this.leftArrow.inputEnabled = true;//enable input
        this.leftArrow.input.pixelPerfectClick = true;//this will the clickable area to shape of the sprite and not a regular rectangle
        this.leftArrow.events.onInputDown.add(this.changeAnimal, this);//add event when user clicks

        //right arrow (next)
        this.rightArrow = this.game.add.sprite(this.game.world.centerX + 210, this.game.world.centerY - 50, 'arrowImageKey');
        this.rightArrow.anchor.setTo = (0.5, 0.5);
        this.rightArrow.customParams = {direction: 1};

        //event: when right arrow is clicked
        this.rightArrow.inputEnabled = true;//enable input
        this.rightArrow.input.pixelPerfectClick = true;//this will the clickable area to shape of the sprite and not a regular rectangle
        this.rightArrow.events.onInputDown.add(this.changeAnimal, this);//add event when user clicks

	},
	//this function is called multiple times to handle the requests when game is live
	update: function(){

	},

    //changeAnimal function
    changeAnimal: function(sprite, event){
        //console.log(sprite, event);
        console.log("Change");
    },

    //animateAnimal function
    animateAnimal: function(sprite, event){
        //console.log(sprite, event);
        console.log("Animate");
    }

};

//add state to the main game
game.state.add('GameState', GameState);

//to launch the game
game.state.start('GameState');<|endoftext|>


<commit_before>import 'moment/locale/fr.js';

import React from 'react';
import ReactDOM from 'react-dom';
import { DatePicker, DatePickerInput } from '../src';

import '../src/style.scss';

class Example extends React.Component {

  state = {
    datePickerDate: '2015-05-13',
    datePickerInputDate: null,
    datePickerInputDate2: null,
    showInput: true
  }

  toggleInput = () => this.setState({ showInput: !this.state.showInput })

  onClear = () => this.setState({ datePickerDate: null })

  log = (...x) => console.log(...x) // eslint-disable-line no-console

  resetState = () => this.setState({ datePickerInputDate2: undefined })

  render() {
    const yesterday = new Date();
    yesterday.setDate(yesterday.getDate() - 1);
    return (

DatePickerInput

        <button onClick={this.toggleInput}>toggle DatePickerInput</button>

onChange(jsDate, dateString)

dateString = "{this.state.datePickerInputDate}"

        {this.state.showInput &&

            <DatePickerInput
              displayFormat='DD/MM/YYYY'
              returnFormat='YYYY-MM-DD'
              className='my-react-component'
              onChange={(jsDate, dateString) => this.setState({ datePickerInputDate: dateString })}
              onShow={this.log.bind(this, 'show')}
              onHide={this.log.bind(this, 'hide')}
              showOnInputClick
              placeholder='placeholder'
              locale='de'
              onClear={this.onClear}
            />

        }

DatePicker (fixed calendar component)

onChange(jsDate)

jsDate = {String(this.state.datePickerDate)}

        <DatePicker
          className='my-react-datepicker'
          locale='fr'
          value={this.state.datePickerDate}
          onChange={(jsDate) => this.setState({ datePickerDate: jsDate })}
        />

VALUE LINK

        <button onClick={this.resetState}>reset state</button>

jsDate = {String(this.state.datePickerInputDate2)}

          <DatePickerInput
            displayFormat='DD/MM/YYYY'
            returnFormat='YYYY-MM-DD'
            className='my-react-component'
            defaultValue={yesterday}
            valueLink={{
              value: this.state.datePickerInputDate2,
              requestChange: datePickerInputDate2 => this.setState({ datePickerInputDate2 })
            }}
            showOnInputClick
            placeholder='placeholder'
            locale='de'
          />

    );
  }
}

ReactDOM.render(<Example />, document.getElementById('container'));
<commit_msg>update examples<commit_after>import 'moment/locale/fr.js';

import React from 'react';
import ReactDOM from 'react-dom';
import { DatePicker, DatePickerInput } from '../src';

import '../src/style.scss';

class Example extends React.Component {

  state = {
    datePickerDate: '2015-05-13',
    datePickerInputDate: null,
    datePickerInputDate2: null,
    showInput: true,
    disabled: false
  }

  toggleInput = () => this.setState({ showInput: !this.state.showInput })

  onClear = () => this.setState({ datePickerDate: null })

  log = (...x) => console.log(...x) // eslint-disable-line no-console

  resetState = () => this.setState({ datePickerInputDate2: undefined })

  render() {
    const yesterday = new Date();
    yesterday.setDate(yesterday.getDate() - 1);
    return (

DatePickerInput

        <button onClick={this.toggleInput}>toggle DatePickerInput</button>

onChange(jsDate, dateString)

dateString = "{this.state.datePickerInputDate}"

        <button onClick={() => this.setState({ disabled: !this.state.disabled })}>toggle disable</button>
        {this.state.showInput &&

            <DatePickerInput
              disabled={this.state.disabled}
              displayFormat='DD/MM/YYYY'
              returnFormat='YYYY-MM-DD'
              className='my-react-component'
              onChange={(jsDate, dateString) => this.setState({ datePickerInputDate: dateString })}
              onShow={this.log.bind(this, 'show')}
              onHide={this.log.bind(this, 'hide')}
              showOnInputClick
              placeholder='placeholder'
              locale='de'
              onClear={this.onClear}
            />

        }

DatePicker (fixed calendar component)

onChange(jsDate)

jsDate = {String(this.state.datePickerDate)}

        <DatePicker
          className='my-react-datepicker'
          locale='fr'
          value={this.state.datePickerDate}
          onChange={(jsDate) => this.setState({ datePickerDate: jsDate })}
        />

VALUE LINK

        <button onClick={this.resetState}>reset state</button>

jsDate = {String(this.state.datePickerInputDate2)}

          <DatePickerInput
            displayFormat='DD/MM/YYYY'
            returnFormat='YYYY-MM-DD'
            className='my-react-component'
            defaultValue={yesterday}
            valueLink={{
              value: this.state.datePickerInputDate2,
              requestChange: datePickerInputDate2 => this.setState({ datePickerInputDate2 })
            }}
            showOnInputClick
            placeholder='placeholder'
            locale='de'
          />

    );
  }
}

ReactDOM.render(<Example />, document.getElementById('container'));
<|endoftext|>


<commit_before>var deepstream = require( 'deepstream.io-client-js' );
var conf = require( '../conf' ).client;

var latency = [];

module.exports = function( clientID, clientType, deepstreamURL ) {

	function updateRecord( record, data ) {
		setTimeout( function() {
			data.timestamp = Date.now();
			record.set( data );
		}, conf.messageFrequency );
	}

	var ds = deepstream( deepstreamURL );
	var userName = clientID + '-' + clientType;

	ds.on( 'error', function( e ) {
		console.log( 'error occured', arguments );
	} );

	ds.login( {
		username: userName
	}, function( success, errorEvent, errorMessage ) {
		var record = ds.record.getRecord( 'perf/' + clientID );

		record.subscribe( clientType === 'ping' ? 'pong' : 'ping', function( data ) {
			var lastTimestamp = record.get( 'timestamp' );

			if( record.get( 'ping' ) === conf.messageLimit ) {
				ds.close();
				if( typeof window === 'undefined' ) {
					process.send( {
						clientID: clientID,
						type: clientType,
						latency: latency
					} );
				} else {
					console.log( 'Message limit reached' );
				}
			} else if( clientType === 'ping' && !( record.get( 'ping' ) === 1 && record.get( 'pong' ) === 0 ) ) {
				updateRecord( record, {
					'ping': record.get( 'ping' ) + 1,
					'pong': record.get( 'pong' ),
				} );
				conf.calculateLatency && latency.push( Date.now() - lastTimestamp );
			} else if( clientType === 'pong' ) {
				updateRecord( record, {
					'ping': record.get( 'ping' ),
					'pong': record.get( 'pong' ) + 1,
				} );
			}
		} );

		if( clientType === 'ping' ) {
			record.set( {
				ping: 1,
				pong: 0,
				timestamp: Date.now()
			} );
		}

	} );

}
<commit_msg>Adding temp logging<commit_after>var deepstream = require( 'deepstream.io-client-js' );
var conf = require( '../conf' ).client;

var latency = [];

module.exports = function( clientID, clientType, deepstreamURL ) {

	function updateRecord( record, data ) {
		setTimeout( function() {
			data.timestamp = Date.now();
			record.set( data );
		}, conf.messageFrequency );
	}

	var ds = deepstream( deepstreamURL );
	var userName = clientID + '-' + clientType;

	ds.on( 'error', function( e ) {
		console.log( 'error occured', arguments );
	} );

	ds.login( {
		username: userName
	}, function( success, errorEvent, errorMessage ) {
		var record = ds.record.getRecord( 'perf/' + clientID );

		record.subscribe( clientType === 'ping' ? 'pong' : 'ping', function( data ) {
			var lastTimestamp = record.get( 'timestamp' );

			if( record.get( 'ping' ) === conf.messageLimit ) {
				ds.close();
				if( typeof window === 'undefined' ) {
					process.send( {
						clientID: clientID,
						type: clientType,
						latency: latency
					} );
					var latencyLog = [
						'Process ' + clientID + ' completed',
						'\nLatency: ' + latency
					].join( '\n' );
					conf.logLatency && console.log( latencyLog );
				} else {
					console.log( 'Message limit reached' );
				}
			} else if( clientType === 'ping' && !( record.get( 'ping' ) === 1 && record.get( 'pong' ) === 0 ) ) {
				updateRecord( record, {
					'ping': record.get( 'ping' ) + 1,
					'pong': record.get( 'pong' ),
				} );
				conf.calculateLatency && latency.push( Date.now() - lastTimestamp );
			} else if( clientType === 'pong' ) {
				updateRecord( record, {
					'ping': record.get( 'ping' ),
					'pong': record.get( 'pong' ) + 1,
				} );
			}
		} );

		if( clientType === 'ping' ) {
			record.set( {
				ping: 1,
				pong: 0,
				timestamp: Date.now()
			} );
		}

	} );

}
<|endoftext|>


<commit_before>var ModuleTranspiler = require('broccoli-es6modules');
var Funnel = require('broccoli-funnel');
var mergeTrees = require('broccoli-merge-trees');
var concat = require('broccoli-concat');
var replace = require('broccoli-replace');
var peg = require('broccoli-pegjs');
var es6to5 = require('broccoli-6to5-transpiler');
var broccoliStew = require('broccoli-stew');
var broccoliCoffee = require('broccoli-coffee');
var injectLivereload = require('broccoli-inject-livereload');

var outputDir = '/';

// Turn ES6 to ES5, without module transpilation
function transpileES6(tree){
  return es6to5(tree, {
    blacklist: ['es6.modules', 'useStrict']
  });
}

function buildSrcTree(){
  var lib = new Funnel('lib', {
    exclude: ['**/*.rb', '**/*.pegjs'],
    destDir: outputDir + 'emblem'
  });

  lib = broccoliStew.mv(lib, 'emblem/main.js', 'emblem.js');
  lib = transpileES6(lib);
  return lib;
}

function buildPegTree(){
  var pegTree = new Funnel('lib', {
    include: ['*.pegjs'],
    destDir: outputDir + 'emblem'
  });

  pegTree = peg(pegTree, {
    wrapper: function (src, parser) {
      return ['/*jshint newcap: false, laxbreak: true */',
              "import { generateBuilder } from './ast-builder';",
              "import { INDENT_SYMBOL, DEDENT_SYMBOL, UNMATCHED_DEDENT_SYMBOL, TERM_SYMBOL } from './preprocessor';",
              'var Parser = ' + parser + ';',
              'var parse = Parser.parse, ParserSyntaxError = Parser.SyntaxError;',
              'export {ParserSyntaxError, parse};',
              'export default parse;'].join('\n');
    }
  });

  return pegTree;
}

function buildDistTree(srcTree){
  var amdTree = new ModuleTranspiler(srcTree, {format: 'amd'});
  var cjsTree = new ModuleTranspiler(srcTree, {format: 'cjs'});

  cjsTree = broccoliStew.mv(cjsTree, outputDir + '/cjs');

  amdTree = concat(amdTree, {
    inputFiles: ['**/*.js'],
    outputFile: outputDir + 'emblem.amd.js',
    wrapInFunction: false
  });

  return mergeTrees([amdTree, cjsTree]);
}

function buildSrcDepsTree(){
  var stringScannerTree = new Funnel('node_modules/StringScanner/lib', {
    include: ['StringScanner.js']
  });

  var header = 'var module = {};\n';
  var footer = 'export default module.exports;';

  return concat(stringScannerTree, {
    inputFiles: ['StringScanner.js'],
    outputFile: outputDir + 'string-scanner.js',
    header: header,
    footer: footer,
    wrapInFunction: false
  });
}

function buildTestTree(){
  // all test code files
  var testTree = new Funnel('tests', {
    include: ['**/*.js', '**/*.coffee']
  });

  // all test asset files
  var testAssetsTree = new Funnel('tests', {
    exclude: ['**/*.js', '**/*.coffee']
  });

  testAssetsTree = mergeTrees([testAssetsTree, buildTestSupportTree()]);

  // rewrite .coffee files to .js files
  testTree = broccoliCoffee(testTree, {bare:true});

  // turn es6 to es5, without modules
  testTree = transpileES6(testTree);

  // transpile modules to amd
  var amdTestTree = new ModuleTranspiler(testTree, { format: 'amd' });

  // combine AMD files
  amdTestTree = concat(amdTestTree, {
    inputFiles: ['**/*.js'],
    outputFile: outputDir + 'emblem-tests.amd.js',
    wrapInFunction: false
  });

  var cjsTestTree = new ModuleTranspiler(testTree, { format: 'cjs' });

  cjsTestTree = broccoliStew.mv(cjsTestTree, outputDir + 'cjs/tests');

  testTree = mergeTrees([amdTestTree, testAssetsTree]);
  // put tests in 'tests/'
  testTree = broccoliStew.mv(testTree, outputDir + 'tests');

  return mergeTrees([ cjsTestTree, testTree ]);
}

function buildTestSupportTree(){
  var qUnitTree = new Funnel('bower_components/qunit', {
    srcDir: 'qunit',
    destDir: 'qunit'
  });

  var loaderTree = new Funnel('bower_components', {
    srcDir: 'loader.js',
    destDir: 'loader.js',
    include: ['loader.js']
  });

  var handlebarsTree = new Funnel('node_modules/handlebars/dist', {
    include: ['handlebars.js'],
    destDir: 'handlebars'
  });

  var jQueryTree = new Funnel('bower_components/jquery/dist', {
    include: ['jquery.js'],
    destDir: 'jquery'
  });

  var emberTree = new Funnel('bower_components/ember', {
    include: ['ember.js'],
    destDir: 'ember'
  });

  return mergeTrees([
    qUnitTree, loaderTree, handlebarsTree, jQueryTree, emberTree]);
}

var srcTree  = mergeTrees(
  [buildSrcTree(), buildPegTree(), buildSrcDepsTree()]
);
var distTree = buildDistTree(srcTree);
var testTree = buildTestTree();
testTree = injectLivereload(testTree);

module.exports = mergeTrees( [distTree, testTree] );
<commit_msg>Replace version in built output fixes #209<commit_after>var ModuleTranspiler = require('broccoli-es6modules');
var Funnel = require('broccoli-funnel');
var mergeTrees = require('broccoli-merge-trees');
var concat = require('broccoli-concat');
var replace = require('broccoli-replace');
var peg = require('broccoli-pegjs');
var es6to5 = require('broccoli-6to5-transpiler');
var broccoliStew = require('broccoli-stew');
var broccoliCoffee = require('broccoli-coffee');
var injectLivereload = require('broccoli-inject-livereload');
var package = require('./package.json');

var outputDir = '/';

// Turn ES6 to ES5, without module transpilation
function transpileES6(tree){
  return es6to5(tree, {
    blacklist: ['es6.modules', 'useStrict']
  });
}

function buildSrcTree(){
  var lib = new Funnel('lib', {
    exclude: ['**/*.rb', '**/*.pegjs'],
    destDir: outputDir + 'emblem'
  });
  lib = replaceVersion(lib, ['emblem/main.js'] );

  lib = broccoliStew.mv(lib, 'emblem/main.js', 'emblem.js');
  lib = transpileES6(lib);
  return lib;
}

function replaceVersion(tree, files){
  return replace(tree, {
    files: files,
    patterns: [ {
      match: /VERSION_STRING_PLACEHOLDER/,
      replacement: package.version,
    } ]
  });
}

function buildPegTree(){
  var pegTree = new Funnel('lib', {
    include: ['*.pegjs'],
    destDir: outputDir + 'emblem'
  });

  pegTree = peg(pegTree, {
    wrapper: function (src, parser) {
      return ['/*jshint newcap: false, laxbreak: true */',
              "import { generateBuilder } from './ast-builder';",
              "import { INDENT_SYMBOL, DEDENT_SYMBOL, UNMATCHED_DEDENT_SYMBOL, TERM_SYMBOL } from './preprocessor';",
              'var Parser = ' + parser + ';',
              'var parse = Parser.parse, ParserSyntaxError = Parser.SyntaxError;',
              'export {ParserSyntaxError, parse};',
              'export default parse;'].join('\n');
    }
  });

  return pegTree;
}

function buildDistTree(srcTree){
  var amdTree = new ModuleTranspiler(srcTree, {format: 'amd'});
  var cjsTree = new ModuleTranspiler(srcTree, {format: 'cjs'});

  cjsTree = broccoliStew.mv(cjsTree, outputDir + '/cjs');

  amdTree = concat(amdTree, {
    inputFiles: ['**/*.js'],
    outputFile: outputDir + 'emblem.amd.js',
    wrapInFunction: false
  });

  return mergeTrees([amdTree, cjsTree]);
}

function buildSrcDepsTree(){
  var stringScannerTree = new Funnel('node_modules/StringScanner/lib', {
    include: ['StringScanner.js']
  });

  var header = 'var module = {};\n';
  var footer = 'export default module.exports;';

  return concat(stringScannerTree, {
    inputFiles: ['StringScanner.js'],
    outputFile: outputDir + 'string-scanner.js',
    header: header,
    footer: footer,
    wrapInFunction: false
  });
}

function buildTestTree(){
  // all test code files
  var testTree = new Funnel('tests', {
    include: ['**/*.js', '**/*.coffee']
  });

  // all test asset files
  var testAssetsTree = new Funnel('tests', {
    exclude: ['**/*.js', '**/*.coffee']
  });

  testAssetsTree = mergeTrees([testAssetsTree, buildTestSupportTree()]);

  // rewrite .coffee files to .js files
  testTree = broccoliCoffee(testTree, {bare:true});

  // turn es6 to es5, without modules
  testTree = transpileES6(testTree);

  // transpile modules to amd
  var amdTestTree = new ModuleTranspiler(testTree, { format: 'amd' });

  // combine AMD files
  amdTestTree = concat(amdTestTree, {
    inputFiles: ['**/*.js'],
    outputFile: outputDir + 'emblem-tests.amd.js',
    wrapInFunction: false
  });

  var cjsTestTree = new ModuleTranspiler(testTree, { format: 'cjs' });

  cjsTestTree = broccoliStew.mv(cjsTestTree, outputDir + 'cjs/tests');

  testTree = mergeTrees([amdTestTree, testAssetsTree]);
  // put tests in 'tests/'
  testTree = broccoliStew.mv(testTree, outputDir + 'tests');

  return mergeTrees([ cjsTestTree, testTree ]);
}

function buildTestSupportTree(){
  var qUnitTree = new Funnel('bower_components/qunit', {
    srcDir: 'qunit',
    destDir: 'qunit'
  });

  var loaderTree = new Funnel('bower_components', {
    srcDir: 'loader.js',
    destDir: 'loader.js',
    include: ['loader.js']
  });

  var handlebarsTree = new Funnel('node_modules/handlebars/dist', {
    include: ['handlebars.js'],
    destDir: 'handlebars'
  });

  var jQueryTree = new Funnel('bower_components/jquery/dist', {
    include: ['jquery.js'],
    destDir: 'jquery'
  });

  var emberTree = new Funnel('bower_components/ember', {
    include: ['ember.js'],
    destDir: 'ember'
  });

  return mergeTrees([
    qUnitTree, loaderTree, handlebarsTree, jQueryTree, emberTree]);
}

var srcTree  = mergeTrees(
  [buildSrcTree(), buildPegTree(), buildSrcDepsTree()]
);
var distTree = buildDistTree(srcTree);
var testTree = buildTestTree();
testTree = injectLivereload(testTree);

module.exports = mergeTrees( [distTree, testTree] );
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

define([
    "firebug/lib/trace",
    "firebug/lib/array",
    "firebug/lib/string",
],
function(FBTrace, Arr, Str) {

// ********************************************************************************************* //
// Constants

var Cu = Components.utils;

var Obj = {};

// ********************************************************************************************* //

Obj.bind = function()  // fn, thisObject, args => thisObject.fn(arguments, args);
{
   var args = Arr.cloneArray(arguments), fn = args.shift(), object = args.shift();
   return function bind() { return fn.apply(object, Arr.arrayInsert(Arr.cloneArray(args), 0, arguments)); };
};

Obj.bindFixed = function() // fn, thisObject, args => thisObject.fn(args);
{
    var args = Arr.cloneArray(arguments), fn = args.shift(), object = args.shift();
    return function() { return fn.apply(object, args); };
};

Obj.extend = function()
{
    if (arguments.length < 2)
    {
        FBTrace.sysout("object.extend; ERROR", arguments);
        throw new Error("Obj.extend on undefined object");
    }

    var newOb = {};
    for (var i = 0, len = arguments.length; i < len; ++i)
    {
        for (var prop in arguments[i])
            newOb[prop] = arguments[i][prop];
    }

    return newOb;
};

Obj.descend = function(prototypeParent, childProperties)
{
    function protoSetter() {};
    protoSetter.prototype = prototypeParent;
    var newOb = new protoSetter();
    for (var n in childProperties)
        newOb[n] = childProperties[n];
    return newOb;
};

// ************************************************************************************************

Obj.isFunction = function(ob)
{
    return typeof(ob) == "function";
}

// ************************************************************************************************

/**
 * Returns true if the passed object has any properties, otherwise returns false.
 *
 * @param {Object} ob Inspected object
 * @param {Object} nonEnumProps If set to true, check also non-enumerable properties (optional)
 * @param {Object} ownPropsOnly If set to true, only check own properties not inherited (optional)
 */
Obj.hasProperties = function(ob, nonEnumProps, ownPropsOnly)
{
    try
    {
        if (!ob)
            return false;

        try
        {
            // This is probably unnecessary in Firefox 19 or so.
            if ("toString" in ob && ob.toString() === "[xpconnect wrapped native prototype]")
                return true;
        }
        catch (exc) {}

        // The default case (both options false) is relatively simple.
        // Just use for..in loop.
        if (!nonEnumProps && !ownPropsOnly)
        {
            for (var name in ob)
                return true;
            return false;
        }

        var type = typeof(ob);
        if (type == "string" && ob.length)
            return true;

        if (type === "number" || type === "boolean" || type === "undefined" || ob === null)
            return false;

        if (nonEnumProps)
            props = Object.getOwnPropertyNames(ob);
        else
            props = Object.keys(ob);

        if (props.length)
            return true;

        // Not interested in inherited properties, bail out.
        if (ownPropsOnly)
            return false;

        // Climb prototype chain.
        var parent = Object.getPrototypeOf(ob);
        if (parent)
            return this.hasProperties(parent, nonEnumProps, ownPropsOnly);
    }
    catch (exc)
    {
        // Primitive (non string) objects will throw an exception when passed into
        // Object.keys or Object.getOwnPropertyNames APIs.
        // There are also many "security error" exceptions I guess none of which are really
        // necessary to display in the FBTrace console, so, remove the tracing for now.
        // if (FBTrace.DBG_ERRORS)
        //     FBTrace.sysout("lib.hasProperties(" + Str.safeToString(ob) + ") ERROR " + exc, exc);

        // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=648560
        if (ob.wrappedJSObject)
            return true;
    }

    return false;
};

Obj.getPrototype = function(ob)
{
    try
    {
        return ob.prototype;
    } catch (exc) {}
    return null;
};

Obj.getUniqueId = function()
{
    return this.getRandomInt(0,65536);
};

Obj.getRandomInt = function(min, max)
{
    return Math.floor(Math.random() * (max - min + 1) + min);
};

// Cross Window instanceof; type is local to this window
Obj.XW_instanceof = function(obj, type)
{
    if (obj instanceof type)
        return true;  // within-window test

    if (!type)
        return false;

    if (!obj)
        return (type == "undefined");

    // compare strings: obj constructor.name to type.name.
    // This is not perfect, we should compare type.prototype to object.__proto__,
    // but mostly code does not change the constructor object.
    do
    {
        // then the function that constructed us is the argument
        if (obj.constructor && obj.constructor.name == type.name)
            return true;
    }
    while(obj = obj.__proto__);  // walk the prototype chain.

    return false;

    // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Property_Inheritance_Revisited
    // /Determining_Instance_Relationships
};

/**
 * Tells if the given property of the provided object is a non-native getter or not.
 * This method depends on PropertyPanel.jsm module available in Firefox 5+
 * isNonNativeGetter has been introduced in Firefox 7
 * The method has been moved to WebConsoleUtils.jsm in Fx 18
 *
 * @param object aObject The object that contains the property.
 * @param string aProp The property you want to check if it is a getter or not.
 * @return boolean True if the given property is a getter, false otherwise.
 */
Obj.isNonNativeGetter = function(obj, propName)
{
    try
    {
        var scope = {};
        Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", scope);

        if (scope.WebConsoleUtils.isNonNativeGetter)
        {
            Obj.isNonNativeGetter = function(obj, propName)
            {
                return scope.WebConsoleUtils.isNonNativeGetter(obj, propName);
            };

            return Obj.isNonNativeGetter(obj, propName);
        }
    }
    catch (err)
    {
        if (FBTrace.DBG_ERRORS)
            FBTrace.sysout("Obj.isNonNativeGetter; EXCEPTION " + err, err);
    }

    // OK, the method isn't available let's use an empty implementation
    Obj.isNonNativeGetter = function()
    {
        if (FBTrace.DBG_ERRORS)
            FBTrace.sysout("Obj.isNonNativeGetter; ERROR built-in method not found!");
        return true;
    };

    return true;
};

// xxxFlorent: [ES6-getPropertyNames]
// http://wiki.ecmascript.org/doku.php?id=harmony:extended_object_api&s=getownpropertynames
/**
 * Gets property names from an object.
 *
 * @param {*} subject The object
 * @return {Array} The property names
 *
 */
Obj.getPropertyNames = Object.getPropertyNames || function(subject)
{
    var props = Object.getOwnPropertyNames(subject);
    var proto = Object.getPrototypeOf(subject);
    while (proto !== null)
    {
        props = props.concat(Object.getOwnPropertyNames(proto));
        proto = Object.getPrototypeOf(proto);
    }
    // only keep unique elements from props (not optimised):
    //    props = [...new Set(props)];
    return Arr.unique(props);
};

// ********************************************************************************************* //

return Obj;

// ********************************************************************************************* //
});
<commit_msg>Recover 986efb32: Fix bug where applying operand 'in' on some things throws an uncatchable error<commit_after>/* See license.txt for terms of usage */

define([
    "firebug/lib/trace",
    "firebug/lib/array",
    "firebug/lib/string",
],
function(FBTrace, Arr, Str) {

// ********************************************************************************************* //
// Constants

var Cu = Components.utils;

var Obj = {};

// ********************************************************************************************* //

Obj.bind = function()  // fn, thisObject, args => thisObject.fn(arguments, args);
{
   var args = Arr.cloneArray(arguments), fn = args.shift(), object = args.shift();
   return function bind() { return fn.apply(object, Arr.arrayInsert(Arr.cloneArray(args), 0, arguments)); };
};

Obj.bindFixed = function() // fn, thisObject, args => thisObject.fn(args);
{
    var args = Arr.cloneArray(arguments), fn = args.shift(), object = args.shift();
    return function() { return fn.apply(object, args); };
};

Obj.extend = function()
{
    if (arguments.length < 2)
    {
        FBTrace.sysout("object.extend; ERROR", arguments);
        throw new Error("Obj.extend on undefined object");
    }

    var newOb = {};
    for (var i = 0, len = arguments.length; i < len; ++i)
    {
        for (var prop in arguments[i])
            newOb[prop] = arguments[i][prop];
    }

    return newOb;
};

Obj.descend = function(prototypeParent, childProperties)
{
    function protoSetter() {};
    protoSetter.prototype = prototypeParent;
    var newOb = new protoSetter();
    for (var n in childProperties)
        newOb[n] = childProperties[n];
    return newOb;
};

// ************************************************************************************************

Obj.isFunction = function(ob)
{
    return typeof(ob) == "function";
}

// ************************************************************************************************

/**
 * Returns true if the passed object has any properties, otherwise returns false.
 *
 * @param {Object} ob Inspected object
 * @param {Object} nonEnumProps If set to true, check also non-enumerable properties (optional)
 * @param {Object} ownPropsOnly If set to true, only check own properties not inherited (optional)
 */
Obj.hasProperties = function(ob, nonEnumProps, ownPropsOnly)
{
    try
    {
        if (!ob)
            return false;

        var type = typeof(ob);
        if (type == "string" && ob.length)
            return true;

        if (type === "number" || type === "boolean" || type === "undefined" || ob === null)
            return false;

        try
        {
            // This is probably unnecessary in Firefox 19 or so.
            if ("toString" in ob && ob.toString() === "[xpconnect wrapped native prototype]")
                return true;
        }
        catch (exc) {}

        // The default case (both options false) is relatively simple.
        // Just use for..in loop.
        if (!nonEnumProps && !ownPropsOnly)
        {
            for (var name in ob)
                return true;
            return false;
        }

        if (nonEnumProps)
            props = Object.getOwnPropertyNames(ob);
        else
            props = Object.keys(ob);

        if (props.length)
            return true;

        // Not interested in inherited properties, bail out.
        if (ownPropsOnly)
            return false;

        // Climb prototype chain.
        var parent = Object.getPrototypeOf(ob);
        if (parent)
            return this.hasProperties(parent, nonEnumProps, ownPropsOnly);
    }
    catch (exc)
    {
        // Primitive (non string) objects will throw an exception when passed into
        // Object.keys or Object.getOwnPropertyNames APIs.
        // There are also many "security error" exceptions I guess none of which are really
        // necessary to display in the FBTrace console, so, remove the tracing for now.
        // if (FBTrace.DBG_ERRORS)
        //     FBTrace.sysout("lib.hasProperties(" + Str.safeToString(ob) + ") ERROR " + exc, exc);

        // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=648560
        if (ob.wrappedJSObject)
            return true;
    }

    return false;
};

Obj.getPrototype = function(ob)
{
    try
    {
        return ob.prototype;
    } catch (exc) {}
    return null;
};

Obj.getUniqueId = function()
{
    return this.getRandomInt(0,65536);
};

Obj.getRandomInt = function(min, max)
{
    return Math.floor(Math.random() * (max - min + 1) + min);
};

// Cross Window instanceof; type is local to this window
Obj.XW_instanceof = function(obj, type)
{
    if (obj instanceof type)
        return true;  // within-window test

    if (!type)
        return false;

    if (!obj)
        return (type == "undefined");

    // compare strings: obj constructor.name to type.name.
    // This is not perfect, we should compare type.prototype to object.__proto__,
    // but mostly code does not change the constructor object.
    do
    {
        // then the function that constructed us is the argument
        if (obj.constructor && obj.constructor.name == type.name)
            return true;
    }
    while(obj = obj.__proto__);  // walk the prototype chain.

    return false;

    // https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Property_Inheritance_Revisited
    // /Determining_Instance_Relationships
};

/**
 * Tells if the given property of the provided object is a non-native getter or not.
 * This method depends on PropertyPanel.jsm module available in Firefox 5+
 * isNonNativeGetter has been introduced in Firefox 7
 * The method has been moved to WebConsoleUtils.jsm in Fx 18
 *
 * @param object aObject The object that contains the property.
 * @param string aProp The property you want to check if it is a getter or not.
 * @return boolean True if the given property is a getter, false otherwise.
 */
Obj.isNonNativeGetter = function(obj, propName)
{
    try
    {
        var scope = {};
        Cu.import("resource://gre/modules/devtools/WebConsoleUtils.jsm", scope);

        if (scope.WebConsoleUtils.isNonNativeGetter)
        {
            Obj.isNonNativeGetter = function(obj, propName)
            {
                return scope.WebConsoleUtils.isNonNativeGetter(obj, propName);
            };

            return Obj.isNonNativeGetter(obj, propName);
        }
    }
    catch (err)
    {
        if (FBTrace.DBG_ERRORS)
            FBTrace.sysout("Obj.isNonNativeGetter; EXCEPTION " + err, err);
    }

    // OK, the method isn't available let's use an empty implementation
    Obj.isNonNativeGetter = function()
    {
        if (FBTrace.DBG_ERRORS)
            FBTrace.sysout("Obj.isNonNativeGetter; ERROR built-in method not found!");
        return true;
    };

    return true;
};

// xxxFlorent: [ES6-getPropertyNames]
// http://wiki.ecmascript.org/doku.php?id=harmony:extended_object_api&s=getownpropertynames
/**
 * Gets property names from an object.
 *
 * @param {*} subject The object
 * @return {Array} The property names
 *
 */
Obj.getPropertyNames = Object.getPropertyNames || function(subject)
{
    var props = Object.getOwnPropertyNames(subject);
    var proto = Object.getPrototypeOf(subject);
    while (proto !== null)
    {
        props = props.concat(Object.getOwnPropertyNames(proto));
        proto = Object.getPrototypeOf(proto);
    }
    // only keep unique elements from props (not optimised):
    //    props = [...new Set(props)];
    return Arr.unique(props);
};

// ********************************************************************************************* //

return Obj;

// ********************************************************************************************* //
});
<|endoftext|>


<commit_before>const extend = require('../utils/extend');

function init (scope) {
  const {
    InteractEvent,
    Interaction,
  } = scope;

  scope.modifiers = { names: [] };

  Interaction.signals.on('new', function (interaction) {
    interaction.startOffset      = { left: 0, right: 0, top: 0, bottom: 0 };
    interaction.modifierOffsets  = {};
    interaction.modifierStatuses = resetStatuses({}, scope.modifiers);
    interaction.modifierResult   = null;
  });

  Interaction.signals.on('action-start' , arg =>
    start(arg, scope.modifiers, arg.interaction.startCoords.page));

  Interaction.signals.on('action-resume', arg => {
    beforeMove(arg, scope.modifiers);
    start(arg, scope.modifiers, arg.interaction.curCoords.page);
  });

  Interaction.signals.on('before-action-move', arg => beforeMove(arg, scope.modifiers));
  Interaction.signals.on('action-end', arg => beforeEnd(arg, scope.modifiers));

  InteractEvent.signals.on('set-xy', arg => setXY(arg, scope.modifiers));
}

function setOffsets (arg, modifiers) {
  const { interaction, pageCoords: page } = arg;
  const { target, element, startOffset } = interaction;
  const rect = target.getRect(element);

  if (rect) {
    startOffset.left = page.x - rect.left;
    startOffset.top  = page.y - rect.top;

    startOffset.right  = rect.right  - page.x;
    startOffset.bottom = rect.bottom - page.y;

    if (!('width'  in rect)) { rect.width  = rect.right  - rect.left; }
    if (!('height' in rect)) { rect.height = rect.bottom - rect.top ; }
  }
  else {
    startOffset.left = startOffset.top = startOffset.right = startOffset.bottom = 0;
  }

  arg.rect = rect;
  arg.interactable = target;
  arg.element = element;

  for (const modifierName of modifiers.names) {
    arg.options = target.options[interaction.prepared.name][modifierName];

    if (!arg.options) {
      continue;
    }

    interaction.modifierOffsets[modifierName] = modifiers[modifierName].setOffset(arg);
  }
}

function setAll (arg, modifiers) {
  const { interaction, statuses, preEnd, requireEndOnly } = arg;
  const result = {
    dx: 0,
    dy: 0,
    changed: false,
    locked: false,
    shouldMove: true,
  };

  arg.modifiedCoords = extend({}, arg.pageCoords);

  for (const modifierName of modifiers.names) {
    const modifier = modifiers[modifierName];
    const options = interaction.target.options[interaction.prepared.name][modifierName];

    if (!shouldDo(options, preEnd, requireEndOnly)) { continue; }

    arg.status = arg.status = statuses[modifierName];
    arg.options = options;
    arg.offset = arg.interaction.modifierOffsets[modifierName];

    modifier.set(arg);

    if (arg.status.locked) {
      arg.modifiedCoords.x += arg.status.dx;
      arg.modifiedCoords.y += arg.status.dy;

      result.dx += arg.status.dx;
      result.dy += arg.status.dy;

      result.locked = true;
    }
  }

  // a move should be fired if:
  //  - there are no modifiers enabled,
  //  - no modifiers are "locked" i.e. have changed the pointer's coordinates, or
  //  - the locked coords have changed since the last pointer move
  result.shouldMove = !arg.status || !result.locked || arg.status.changed;

  return result;
}

function resetStatuses (statuses, modifiers) {
  for (const modifierName of modifiers.names) {
    const status = statuses[modifierName] || {};

    status.dx = status.dy = 0;
    status.modifiedX = status.modifiedY = NaN;
    status.locked = false;
    status.changed = true;

    statuses[modifierName] = status;
  }

  return statuses;
}

function start ({ interaction }, modifiers, pageCoords) {
  const arg = {
    interaction,
    pageCoords,
    startOffset: interaction.startOffset,
    statuses: interaction.modifierStatuses,
    preEnd: false,
    requireEndOnly: false,
  };

  setOffsets(arg, modifiers);
  resetStatuses(arg.statuses, modifiers);

  arg.pageCoords = extend({}, interaction.startCoords.page);
  interaction.modifierResult = setAll(arg, modifiers);
}

function beforeMove ({ interaction, preEnd, interactingBeforeMove }, modifiers) {
  const modifierResult = setAll(
    {
      interaction,
      preEnd,
      pageCoords: interaction.curCoords.page,
      statuses: interaction.modifierStatuses,
      requireEndOnly: false,
    }, modifiers);

  interaction.modifierResult = modifierResult;

  // don't fire an action move if a modifier would keep the event in the same
  // cordinates as before
  if (!modifierResult.shouldMove && interactingBeforeMove) {
    return false;
  }
}

function beforeEnd ({ interaction, event }, modifiers) {
  for (const modifierName of modifiers.names) {
    const options = interaction.target.options[interaction.prepared.name][modifierName];

    // if the endOnly option is true for any modifier
    if (shouldDo(options, true, true)) {
      // fire a move event at the modified coordinates
      interaction.doMove({ event, preEnd: true });
      break;
    }
  }
}

function setXY (arg, modifiers) {
  const { iEvent, interaction } = arg;
  const modifierArg = extend({}, arg);

  for (let i = 0; i < modifiers.names.length; i++) {
    const modifierName = modifiers.names[i];
    modifierArg.options = interaction.target.options[interaction.prepared.name][modifierName];

    if (!modifierArg.options) {
      continue;
    }

    const modifier = modifiers[modifierName];

    modifierArg.status = interaction.modifierStatuses[modifierName];

    iEvent[modifierName] = modifier.modifyCoords(modifierArg);
  }
}

function shouldDo (options, preEnd, requireEndOnly) {
  return (options && options.enabled
    && (preEnd || !options.endOnly)
    && (!requireEndOnly || options.endOnly));
}

module.exports = {
  init,
  setOffsets,
  setAll,
  resetStatuses,
  start,
  beforeMove,
  beforeEnd,
  shouldDo,
};
<commit_msg>modifiers/base: do preEnd on before-action-end<commit_after>const extend = require('../utils/extend');

function init (scope) {
  const {
    InteractEvent,
    Interaction,
  } = scope;

  scope.modifiers = { names: [] };

  Interaction.signals.on('new', function (interaction) {
    interaction.startOffset      = { left: 0, right: 0, top: 0, bottom: 0 };
    interaction.modifierOffsets  = {};
    interaction.modifierStatuses = resetStatuses({}, scope.modifiers);
    interaction.modifierResult   = null;
  });

  Interaction.signals.on('action-start' , arg =>
    start(arg, scope.modifiers, arg.interaction.startCoords.page));

  Interaction.signals.on('action-resume', arg => {
    beforeMove(arg, scope.modifiers);
    start(arg, scope.modifiers, arg.interaction.curCoords.page);
  });

  Interaction.signals.on('before-action-move', arg => beforeMove(arg, scope.modifiers));
  Interaction.signals.on('before-action-end', arg => beforeEnd(arg, scope.modifiers));

  InteractEvent.signals.on('set-xy', arg => setXY(arg, scope.modifiers));
}

function setOffsets (arg, modifiers) {
  const { interaction, pageCoords: page } = arg;
  const { target, element, startOffset } = interaction;
  const rect = target.getRect(element);

  if (rect) {
    startOffset.left = page.x - rect.left;
    startOffset.top  = page.y - rect.top;

    startOffset.right  = rect.right  - page.x;
    startOffset.bottom = rect.bottom - page.y;

    if (!('width'  in rect)) { rect.width  = rect.right  - rect.left; }
    if (!('height' in rect)) { rect.height = rect.bottom - rect.top ; }
  }
  else {
    startOffset.left = startOffset.top = startOffset.right = startOffset.bottom = 0;
  }

  arg.rect = rect;
  arg.interactable = target;
  arg.element = element;

  for (const modifierName of modifiers.names) {
    arg.options = target.options[interaction.prepared.name][modifierName];

    if (!arg.options) {
      continue;
    }

    interaction.modifierOffsets[modifierName] = modifiers[modifierName].setOffset(arg);
  }
}

function setAll (arg, modifiers) {
  const { interaction, statuses, preEnd, requireEndOnly } = arg;
  const result = {
    dx: 0,
    dy: 0,
    changed: false,
    locked: false,
    shouldMove: true,
  };

  arg.modifiedCoords = extend({}, arg.pageCoords);

  for (const modifierName of modifiers.names) {
    const modifier = modifiers[modifierName];
    const options = interaction.target.options[interaction.prepared.name][modifierName];

    if (!shouldDo(options, preEnd, requireEndOnly)) { continue; }

    arg.status = arg.status = statuses[modifierName];
    arg.options = options;
    arg.offset = arg.interaction.modifierOffsets[modifierName];

    modifier.set(arg);

    if (arg.status.locked) {
      arg.modifiedCoords.x += arg.status.dx;
      arg.modifiedCoords.y += arg.status.dy;

      result.dx += arg.status.dx;
      result.dy += arg.status.dy;

      result.locked = true;
    }
  }

  // a move should be fired if:
  //  - there are no modifiers enabled,
  //  - no modifiers are "locked" i.e. have changed the pointer's coordinates, or
  //  - the locked coords have changed since the last pointer move
  result.shouldMove = !arg.status || !result.locked || arg.status.changed;

  return result;
}

function resetStatuses (statuses, modifiers) {
  for (const modifierName of modifiers.names) {
    const status = statuses[modifierName] || {};

    status.dx = status.dy = 0;
    status.modifiedX = status.modifiedY = NaN;
    status.locked = false;
    status.changed = true;

    statuses[modifierName] = status;
  }

  return statuses;
}

function start ({ interaction }, modifiers, pageCoords) {
  const arg = {
    interaction,
    pageCoords,
    startOffset: interaction.startOffset,
    statuses: interaction.modifierStatuses,
    preEnd: false,
    requireEndOnly: false,
  };

  setOffsets(arg, modifiers);
  resetStatuses(arg.statuses, modifiers);

  arg.pageCoords = extend({}, interaction.startCoords.page);
  interaction.modifierResult = setAll(arg, modifiers);
}

function beforeMove ({ interaction, preEnd, interactingBeforeMove }, modifiers) {
  const modifierResult = setAll(
    {
      interaction,
      preEnd,
      pageCoords: interaction.curCoords.page,
      statuses: interaction.modifierStatuses,
      requireEndOnly: false,
    }, modifiers);

  interaction.modifierResult = modifierResult;

  // don't fire an action move if a modifier would keep the event in the same
  // cordinates as before
  if (!modifierResult.shouldMove && interactingBeforeMove) {
    return false;
  }
}

function beforeEnd ({ interaction, event, iEvent: endEvent }, modifiers) {
  for (const modifierName of modifiers.names) {
    const options = interaction.target.options[interaction.prepared.name][modifierName];

    // if the endOnly option is true for any modifier
    if (shouldDo(options, true, true)) {
      // fire a move event at the modified coordinates
      interaction.doMove({ event, preEnd: true });
      // update the end event's coords to match the latest move event
      for (const coord of ['pageX', 'pageY', 'clientX', 'clientY']) {
        endEvent[coord] = interaction.prevEvent[coord];
      }
      break;
    }
  }
}

function setXY (arg, modifiers) {
  const { iEvent, interaction } = arg;
  const modifierArg = extend({}, arg);

  for (let i = 0; i < modifiers.names.length; i++) {
    const modifierName = modifiers.names[i];
    modifierArg.options = interaction.target.options[interaction.prepared.name][modifierName];

    if (!modifierArg.options) {
      continue;
    }

    const modifier = modifiers[modifierName];

    modifierArg.status = interaction.modifierStatuses[modifierName];

    iEvent[modifierName] = modifier.modifyCoords(modifierArg);
  }
}

function shouldDo (options, preEnd, requireEndOnly) {
  return (options && options.enabled
    && (preEnd || !options.endOnly)
    && (!requireEndOnly || options.endOnly));
}

module.exports = {
  init,
  setOffsets,
  setAll,
  resetStatuses,
  start,
  beforeMove,
  beforeEnd,
  shouldDo,
};
<|endoftext|>


<commit_before>/*
 |--------------------------------------------------------------------------
 | This file contains examples of how to use this plugin
 |--------------------------------------------------------------------------
 |
 | To see what the documents generated by these examples looks like you can open
 | ´examples.html´ or go to http://simonbengtsson.github.io/jsPDF-AutoTable.
 |
 | To make it possible to view each example in examples.html some extra code
 | are added to the examples below. For example they return their jspdf
 | doc instance and gets generated data from the library faker.js. However you
 | can of course use this plugin how you wish and the simplest first example
 | below would look like this without any extras:
 |
 | var columns = ["ID", "Name", "Age", "City"];
 |
 | var data = [
 |     [1, "Jonathan", 25, "Gothenburg"],
 |     [2, "Simon", 23, "Gothenburg"],
 |     [3, "Hanna", 21, "Stockholm"]
 | ];
 |
 | var doc = new jsPDF('p', 'pt');
 | doc.autoTable(columns, data);
 | doc.save("table.pdf");
 |
 */

var faker = window.faker;
var base64Img = null;

var examples = {};

// Default - shows what a default table looks like
examples.auto = function () {
    var doc = new jsPDF();
    doc.autoTable(getColumns(), getData());
    return doc;
};

// Minimal - shows how compact tables can be drawn
examples.minimal = function () {
    var doc = new jsPDF();
    doc.autoTable(getColumns(), getData(), {
        tableWidth: 'wrap',
        styles: {cellPadding: 0.5, fontSize: 8}
    });
    return doc;
};

// Long data - shows how the overflow features looks and can be used
examples.long = function () {
    var doc = new jsPDF('l');
    var columnsLong = getColumns().concat([
        {title: "Title with\nlinebreak", dataKey: "text2"},
        {title: "Long text column", dataKey: "text"},
    ]);

    doc.text(7, 15, "Overflow 'ellipsize' (default)");
    doc.autoTable(columnsLong, getData(), {
        startY: 20,
        margin: {horizontal: 7},
        styles: {columnWidth: 'wrap'},
        columnStyles: {text: {columnWidth: 'auto'}}
    });

    doc.text("Overflow 'hidden'", 7, doc.autoTable.previous.finalY + 10);
    doc.autoTable(columnsLong, getData(), {
        startY: doc.autoTable.previous.finalY + 15,
        margin: {horizontal: 7},
        styles: {overflow: 'hidden', columnWidth: 'wrap'},
        columnStyles: {text: {columnWidth: 'auto'}}
    });

    doc.text("Overflow 'linebreak'", 7, doc.autoTable.previous.finalY  + 10);
    doc.autoTable(columnsLong, getData(3), {
        startY: doc.autoTable.previous.finalY + 15,
        margin: {horizontal: 7},
        bodyStyles: {valign: 'top'},
        styles: {overflow: 'linebreak', columnWidth: 'wrap'},
        columnStyles: {text: {columnWidth: 'auto'}}
    });

    return doc;
};

// Content - shows how tables can be integrated with any other pdf content
examples.content = function () {
    var doc = new jsPDF();

    doc.setFontSize(18);
    doc.text('A story about a person', 14, 22);
    doc.setFontSize(11);
    doc.setTextColor(100);
    var text = doc.splitTextToSize(shuffleSentence(faker.lorem.words(55)) + '.', doc.internal.pageSize.width - 35, {});
    doc.text(text, 14, 30);

    var cols = getColumns();
    cols.splice(0, 2);
    doc.autoTable(cols, getData(40), {startY: 50, showHeader: 'firstPage'});

    doc.text(text, 14, doc.autoTable.previous.finalY + 10);

    return doc;
};

// Multiple - shows how multiple tables can be drawn both horizontally and vertically
examples.multiple = function () {
    var doc = new jsPDF();
    doc.setFontSize(22);
    doc.text("Multiple tables", 14, 20);
    doc.setFontSize(12);

    doc.autoTable(getColumns().slice(0, 2), getData(), {
        startY: 30,
        pageBreak: 'avoid',
        margin: {right: 107}
    });

    doc.autoTable(getColumns().slice(0, 2), getData(), {
        startY: 30,
        pageBreak: 'avoid',
        margin: {left: 107}
    });

    for (var j = 0; j < 6; j++) {
        doc.autoTable(getColumns(), getData(9), {
            startY: doc.autoTable.previous.finalY + 10,
            pageBreak: 'avoid',
        });
    }

    return doc;
};

// From html - shows how pdf tables can be be drawn from html tables
examples.html = function () {
    var doc = new jsPDF();
    doc.text("From HTML", 14, 16);
    var elem = document.getElementById("basic-table");
    var res = doc.autoTableHtmlToJson(elem);
    doc.autoTable(res.columns, res.data, {startY: 20});

    doc.text("From HTML with CSS", 14, 80);
    doc.autoTable(90, {fromHtml: "#basic-table", useCssStyles: true});

    return doc;
};

// Header and footers - shows how header and footers can be drawn
examples['header-footer'] = function () {
    var doc = new jsPDF();
    var totalPagesExp = "{total_pages_count_string}";

    var pageContent = function (data) {
        // HEADER
        doc.setFontSize(20);
        doc.setTextColor(40);
        doc.setFontStyle('normal');
        if (base64Img) {
            doc.addImage(base64Img, 'JPEG', data.settings.margin.left, 15, 10, 10);
        }
        doc.text("Report", data.settings.margin.left + 15, 22);

        // FOOTER
        var str = "Page " + data.pageCount;
        // Total page number plugin only available in jspdf v1.0+
        if (typeof doc.putTotalPages === 'function') {
            str = str + " of " + totalPagesExp;
        }
        doc.setFontSize(10);
        doc.text(str, data.settings.margin.left, doc.internal.pageSize.height - 10);
    };

    doc.autoTable(getColumns(), getData(40), {
        addPageContent: pageContent,
        margin: {top: 30}
    });

    // Total page number plugin only available in jspdf v1.0+
    if (typeof doc.putTotalPages === 'function') {
        doc.putTotalPages(totalPagesExp);
    }

    return doc;
};

// Minimal - shows how compact tables can be drawn
examples.defaults = function () {
    // Global defaults
    jsPDF.autoTableSetDefaults({
        columnStyles: {id: {fontStyle: 'bold'}},
        headerStyles: {fillColor: 0},
    });

    var doc = new jsPDF();

    // Document defaults
    doc.autoTableSetDefaults({
        headerStyles: {fillColor: [155, 89, 182]}, // Purple
        margin: {top: 25},
        addPageContent: function(data) {
            doc.setFontSize(20);
            doc.text('Document specific header', data.settings.margin.left, 20);
        }
    });

    doc.autoTable(getColumns(), getData());

    doc.addPage();

    doc.autoTable(getColumns(), getData(), {
        // Will override document and global headerStyles
        headerStyles: {fillColor: [231, 76, 60]} // Red
    });

    // Reset defaults
    doc.autoTableSetDefaults(null);
    jsPDF.autoTableSetDefaults(null);

    return doc;
};

// Horizontal - shows how tables can be drawn with horizontal headers
examples.horizontal = function () {
    var doc = new jsPDF();
    doc.autoTable(getColumns().splice(1, 4), getData(), {
        showHeader: 'never',
        columnStyles: {
            name: {fillColor: [41, 128, 185], textColor: 255, fontStyle: 'bold'}
        }
    });
    return doc;
};

// Custom style - shows how custom styles can be applied to tables
examples.spans = function () {
    var doc = new jsPDF('p', 'pt');
    doc.setFontSize(12);
    doc.setTextColor(0);
    doc.setFontStyle('bold');
    doc.text('Col and row span', 40, 50);
    let cols = getColumns();
    var data = getData(80);
    data.sort(function (a, b) {
        return parseFloat(b.expenses) - parseFloat(a.expenses);
    });
    data = data.concat(data);
    data.unshift({id: 'Priority Group'});
    data.splice(6, 0, {id: {content: 'Other Groups', colSpan: cols.length, styles: {fontStyle: 'bold', halign: 'center'}}});
    doc.autoTable(cols, data, {
        theme: 'grid',
        startY: 60,
        margin: {bottom: 0},
        createdCell: function(cell, data) {
            if (data.column.dataKey === 'id') {
                // Colspan styles
                if (data.row.index === 0) {
                    cell.styles.textColor = [192, 57, 43];
                    cell.styles.fontStyle = 'bold';
                    cell.styles.halign = 'center';
                    cell.colSpan = data.table.columns.length;
                }

                // Rowspan
                if (data.row.index % 5 === 2 && data.row.index !== 2 || data.row.index == 1) {
                    cell.rowSpan = 5;
                }
            }
        }
    });
    return doc;
};

// Themes - shows how the different themes looks
examples.themes = function () {
    var doc = new jsPDF();
    doc.setFontSize(12);
    doc.setFontStyle('bold');

    doc.text('Theme "striped"', 14, 16);
    doc.autoTable(getColumns(), getData(), {startY: 20});

    doc.text('Theme "grid"', 14, doc.autoTable.previous.finalY + 10);
    doc.autoTable(getColumns(), getData(), {startY: doc.autoTable.previous.finalY + 14, theme: 'grid'});

    doc.text('Theme "plain"', 14, doc.autoTable.previous.finalY + 10);
    doc.autoTable(getColumns(), getData(), {startY: doc.autoTable.previous.finalY + 14, theme: 'plain'});

    return doc;
};

// Custom style - shows how custom styles can be applied to tables
examples.custom = function () {
    var doc = new jsPDF();
    doc.autoTable(getColumns().slice(1, 5), getData(20), {
        tableLineColor: [189, 195, 199],
        tableLineWidth: 0.75,
        styles: {
            font: 'courier',
            lineColor: [44, 62, 80],
            lineWidth: 0.75
        },
        headerStyles: {
            fillColor: [44, 62, 80],
            fontSize: 15
        },
        bodyStyles: {
            fillColor: [52, 73, 94],
            textColor: 240
        },
        alternateRowStyles: {
            fillColor: [74, 96, 117]
        },
        columnStyles: {
            email: {
                fontStyle: 'bold'
            }
        },
        /*parsedInput: function (cell, data) {
            if (data.column.dataKey === 'expenses') {
                cell.styles.halign = 'right';
                if (cell.raw > 600) {
                    cell.styles.textColor = [255, 100, 100];
                    cell.styles.fontStyle = 'bolditalic';
                }
                cell.text = '$' + cell.text;
            } else if (data.column.dataKey === 'name') {
                cell.text = cell.raw.split(' ')[0]; // only first name
            }
        }*/
    });
    return doc;
};

/*
 |--------------------------------------------------------------------------
 | Below is some helper functions for the examples
 |--------------------------------------------------------------------------
 */

// Returns a new array each time to avoid pointer issues
var getColumns = function () {
    return [
        {title: "ID", dataKey: "id"},
        {title: "Name", dataKey: "name"},
        {title: "Email", dataKey: "email"},
        {title: "City", dataKey: "city"},
        {title: "Expenses", dataKey: "expenses"}
    ];
};

// Uses the faker.js library to get random data.
function getData(rowCount) {
    rowCount = rowCount || 4;
    //var sentence = "Minima quis totam nobis nihil et molestiae architecto accusantium qui necessitatibus sit ducimus cupiditate qui ullam et aspernatur esse et dolores ut voluptatem odit quasi ea sit ad sint voluptatem est dignissimos voluptatem vel adipisci facere consequuntur et reprehenderit cum unde debitis ab cumque sint quo ut officiis rerum aut quia quia expedita ut consectetur animiqui voluptas suscipit Monsequatur";
    var sentence = faker.lorem.words(20);
    var data = [];
    for (var j = 1; j <= rowCount; j++) {
        data.push({
            id: j,
            name: faker.name.findName(),
            email: faker.internet.email(),
            country: faker.address.country(),
            city: faker.address.city(),
            expenses: faker.finance.amount(),
            text: shuffleSentence(sentence),
            text2: faker.lorem.words(1)
        });
    }
    return data;
}

function shuffleSentence(words) {
    if (typeof words === 'string') return words;
    words = words || faker.lorem.words(8);
    var str = faker.helpers.shuffle(words).join(' ').trim();
    return str.charAt(0).toUpperCase() + str.slice(1);
}

imgToBase64('document.jpg', function(base64) {
    base64Img = base64;
});

// You could either use a function similar to this or pre convert an image with for example http://dopiaza.org/tools/datauri
// http://stackoverflow.com/questions/6150289/how-to-convert-image-into-base64-string-using-javascript
function imgToBase64(url, callback) {
    if (!window.FileReader) {
        callback(null);
        return;
    }
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'blob';
    xhr.onload = function() {
        var reader = new FileReader();
        reader.onloadend = function() {
            callback(reader.result.replace('text/xml', 'image/jpeg'));
        };
        reader.readAsDataURL(xhr.response);
    };
    xhr.open('GET', url);
    xhr.send();
}<commit_msg>Revert examples.js to v2.3<commit_after>/*
 |--------------------------------------------------------------------------
 | This file contains examples of how to use this plugin
 |--------------------------------------------------------------------------
 |
 | To see what the documents generated by these examples looks like you can open
 | ´examples.html´ or go to http://simonbengtsson.github.io/jsPDF-AutoTable.
 |
 | To make it possible to view each example in examples.html some extra code
 | are added to the examples below. For example they return their jspdf
 | doc instance and gets generated data from the library faker.js. However you
 | can of course use this plugin how you wish and the simplest first example
 | below would look like this without any extras:
 |
 | var columns = ["ID", "Name", "Age", "City"];
 |
 | var data = [
 |     [1, "Jonathan", 25, "Gothenburg"],
 |     [2, "Simon", 23, "Gothenburg"],
 |     [3, "Hanna", 21, "Stockholm"]
 | ];
 |
 | var doc = new jsPDF('p', 'pt');
 | doc.autoTable(columns, data);
 | doc.save("table.pdf");
 |
 */

var faker = window.faker;
var base64Img = null;

var examples = {};

// Default - shows what a default table looks like
examples.auto = function () {
    var doc = new jsPDF();
    doc.autoTable(getColumns(), getData());
    return doc;
};

// Minimal - shows how compact tables can be drawn
examples.minimal = function () {
    var doc = new jsPDF();
    doc.autoTable(getColumns(), getData(), {
        tableWidth: 'wrap',
        styles: {cellPadding: 0.5, fontSize: 8}
    });
    return doc;
};

// Long data - shows how the overflow features looks and can be used
examples.long = function () {
    var doc = new jsPDF('l');
    var columnsLong = getColumns().concat([
        {title: "Title with\nlinebreak", dataKey: "text2"},
        {title: "Long text column", dataKey: "text"},
    ]);

    doc.text(7, 15, "Overflow 'ellipsize' (default)");
    doc.autoTable(columnsLong, getData(), {
        startY: 20,
        margin: {horizontal: 7},
        styles: {columnWidth: 'wrap'},
        columnStyles: {text: {columnWidth: 'auto'}}
    });

    doc.text("Overflow 'hidden'", 7, doc.autoTable.previous.finalY + 10);
    doc.autoTable(columnsLong, getData(), {
        startY: doc.autoTable.previous.finalY + 15,
        margin: {horizontal: 7},
        styles: {overflow: 'hidden', columnWidth: 'wrap'},
        columnStyles: {text: {columnWidth: 'auto'}}
    });

    doc.text("Overflow 'linebreak'", 7, doc.autoTable.previous.finalY  + 10);
    doc.autoTable(columnsLong, getData(3), {
        startY: doc.autoTable.previous.finalY + 15,
        margin: {horizontal: 7},
        bodyStyles: {valign: 'top'},
        styles: {overflow: 'linebreak', columnWidth: 'wrap'},
        columnStyles: {text: {columnWidth: 'auto'}}
    });

    return doc;
};

// Content - shows how tables can be integrated with any other pdf content
examples.content = function () {
    var doc = new jsPDF();

    doc.setFontSize(18);
    doc.text('A story about a person', 14, 22);
    doc.setFontSize(11);
    doc.setTextColor(100);
    var text = doc.splitTextToSize(shuffleSentence(faker.lorem.words(55)) + '.', doc.internal.pageSize.width - 35, {});
    doc.text(text, 14, 30);

    var cols = getColumns();
    cols.splice(0, 2);
    doc.autoTable(cols, getData(40), {startY: 50, showHeader: 'firstPage'});

    doc.text(text, 14, doc.autoTable.previous.finalY + 10);

    return doc;
};

// Multiple - shows how multiple tables can be drawn both horizontally and vertically
examples.multiple = function () {
    var doc = new jsPDF();
    doc.setFontSize(22);
    doc.text("Multiple tables", 14, 20);
    doc.setFontSize(12);

    doc.autoTable(getColumns().slice(0, 2), getData(), {
        startY: 30,
        pageBreak: 'avoid',
        margin: {right: 107}
    });

    doc.autoTable(getColumns().slice(0, 2), getData(), {
        startY: 30,
        pageBreak: 'avoid',
        margin: {left: 107}
    });

    for (var j = 0; j < 6; j++) {
        doc.autoTable(getColumns(), getData(9), {
            startY: doc.autoTable.previous.finalY + 10,
            pageBreak: 'avoid',
        });
    }

    return doc;
};

// From html - shows how pdf tables can be be drawn from html tables
examples.html = function () {
    var doc = new jsPDF();
    doc.text("From HTML", 14, 16);
    var elem = document.getElementById("basic-table");
    var res = doc.autoTableHtmlToJson(elem);
    doc.autoTable(res.columns, res.data, {startY: 20});
    return doc;
};

// Header and footers - shows how header and footers can be drawn
examples['header-footer'] = function () {
    var doc = new jsPDF();
    var totalPagesExp = "{total_pages_count_string}";

    var pageContent = function (data) {
        // HEADER
        doc.setFontSize(20);
        doc.setTextColor(40);
        doc.setFontStyle('normal');
        if (base64Img) {
            doc.addImage(base64Img, 'JPEG', data.settings.margin.left, 15, 10, 10);
        }
        doc.text("Report", data.settings.margin.left + 15, 22);

        // FOOTER
        var str = "Page " + data.pageCount;
        // Total page number plugin only available in jspdf v1.0+
        if (typeof doc.putTotalPages === 'function') {
            str = str + " of " + totalPagesExp;
        }
        doc.setFontSize(10);
        doc.text(str, data.settings.margin.left, doc.internal.pageSize.height - 10);
    };

    doc.autoTable(getColumns(), getData(40), {
        addPageContent: pageContent,
        margin: {top: 30}
    });

    // Total page number plugin only available in jspdf v1.0+
    if (typeof doc.putTotalPages === 'function') {
        doc.putTotalPages(totalPagesExp);
    }

    return doc;
};

// Minimal - shows how compact tables can be drawn
examples.defaults = function () {
    // Global defaults
    jsPDF.autoTableSetDefaults({
        columnStyles: {id: {fontStyle: 'bold'}},
        headerStyles: {fillColor: 0},
    });

    var doc = new jsPDF();

    // Document defaults
    doc.autoTableSetDefaults({
        headerStyles: {fillColor: [155, 89, 182]}, // Purple
        margin: {top: 25},
        addPageContent: function(data) {
            doc.setFontSize(20);
            doc.text('Document specific header', data.settings.margin.left, 20);
        }
    });

    doc.autoTable(getColumns(), getData());

    doc.addPage();

    doc.autoTable(getColumns(), getData(), {
        // Will override document and global headerStyles
        headerStyles: {fillColor: [231, 76, 60]} // Red
    });

    // Reset defaults
    doc.autoTableSetDefaults(null);
    jsPDF.autoTableSetDefaults(null);

    return doc;
};

// Horizontal - shows how tables can be drawn with horizontal headers
examples.horizontal = function () {
    var doc = new jsPDF();
    doc.autoTable(getColumns().splice(1, 4), getData(), {
        showHeader: 'never',
        columnStyles: {
            name: {fillColor: [41, 128, 185], textColor: 255, fontStyle: 'bold'}
        }
    });
    return doc;
};

// Custom style - shows how custom styles can be applied to tables
examples.spans = function () {
    var doc = new jsPDF('p', 'pt');
    doc.setFontSize(12);
    doc.setTextColor(0);
    doc.setFontStyle('bold');
    doc.text('Col and row span', 40, 50);
    var data = getData(80);
    data.sort(function (a, b) {
        return parseFloat(b.expenses) - parseFloat(a.expenses);
    });
    doc.autoTable(getColumns(), data, {
        theme: 'grid',
        startY: 60,
        drawRow: function (row, data) {
            // Colspan
            doc.setFontStyle('bold');
            doc.setFontSize(10);
            if (row.index === 0) {
                doc.setTextColor(200, 0, 0);
                doc.rect(data.settings.margin.left, row.y, data.table.width, 20, 'S');
                doc.autoTableText("Priority Group", data.settings.margin.left + data.table.width / 2, row.y + row.height / 2, {
                    halign: 'center',
                    valign: 'middle'
                });
                data.cursor.y += 20;
            } else if (row.index === 5) {
                doc.rect(data.settings.margin.left, row.y, data.table.width, 20, 'S');
                doc.autoTableText("Other Groups", data.settings.margin.left + data.table.width / 2, row.y + row.height / 2, {
                    halign: 'center',
                    valign: 'middle'
                });
                data.cursor.y += 20;
            }

            if (row.index % 5 === 0) {
                var posY = row.y + row.height * 6 + data.settings.margin.bottom;
                if (posY > doc.internal.pageSize.height) {
                    data.addPage();
                }
            }
        },
        drawCell: function (cell, data) {
            // Rowspan
            if (data.column.dataKey === 'id') {
                if (data.row.index % 5 === 0) {
                    doc.rect(cell.x, cell.y, data.table.width, cell.height * 5, 'S');
                    doc.autoTableText(data.row.index / 5 + 1 + '', cell.x + cell.width / 2, cell.y + cell.height * 5 / 2, {
                        halign: 'center',
                        valign: 'middle'
                    });
                }
                return false;
            }
        }
    });
    return doc;
};

// Themes - shows how the different themes looks
examples.themes = function () {
    var doc = new jsPDF();
    doc.setFontSize(12);
    doc.setFontStyle('bold');

    doc.text('Theme "striped"', 14, 16);
    doc.autoTable(getColumns(), getData(), {startY: 20});

    doc.text('Theme "grid"', 14, doc.autoTable.previous.finalY + 10);
    doc.autoTable(getColumns(), getData(), {startY: doc.autoTable.previous.finalY + 14, theme: 'grid'});

    doc.text('Theme "plain"', 14, doc.autoTable.previous.finalY + 10);
    doc.autoTable(getColumns(), getData(), {startY: doc.autoTable.previous.finalY + 14, theme: 'plain'});

    return doc;
};

// Custom style - shows how custom styles can be applied to tables
examples.custom = function () {
    var doc = new jsPDF();
    doc.autoTable(getColumns().slice(1, 5), getData(20), {
        tableLineColor: [189, 195, 199],
        tableLineWidth: 0.75,
        styles: {
            font: 'courier',
            lineColor: [44, 62, 80],
            lineWidth: 0.75
        },
        headerStyles: {
            fillColor: [44, 62, 80],
            fontSize: 15
        },
        bodyStyles: {
            fillColor: [52, 73, 94],
            textColor: 240
        },
        alternateRowStyles: {
            fillColor: [74, 96, 117]
        },
        columnStyles: {
            email: {
                fontStyle: 'bold'
            }
        },
        /*parsedInput: function (cell, data) {
         if (data.column.dataKey === 'expenses') {
         cell.styles.halign = 'right';
         if (cell.raw > 600) {
         cell.styles.textColor = [255, 100, 100];
         cell.styles.fontStyle = 'bolditalic';
         }
         cell.text = '$' + cell.text;
         } else if (data.column.dataKey === 'name') {
         cell.text = cell.raw.split(' ')[0]; // only first name
         }
         }*/
    });
    return doc;
};

/*
 |--------------------------------------------------------------------------
 | Below is some helper functions for the examples
 |--------------------------------------------------------------------------
 */

// Returns a new array each time to avoid pointer issues
var getColumns = function () {
    return [
        {title: "ID", dataKey: "id"},
        {title: "Name", dataKey: "name"},
        {title: "Email", dataKey: "email"},
        {title: "City", dataKey: "city"},
        {title: "Expenses", dataKey: "expenses"}
    ];
};

// Uses the faker.js library to get random data.
function getData(rowCount) {
    rowCount = rowCount || 4;
    //var sentence = "Minima quis totam nobis nihil et molestiae architecto accusantium qui necessitatibus sit ducimus cupiditate qui ullam et aspernatur esse et dolores ut voluptatem odit quasi ea sit ad sint voluptatem est dignissimos voluptatem vel adipisci facere consequuntur et reprehenderit cum unde debitis ab cumque sint quo ut officiis rerum aut quia quia expedita ut consectetur animiqui voluptas suscipit Monsequatur";
    var sentence = faker.lorem.words(20);
    var data = [];
    for (var j = 1; j <= rowCount; j++) {
        data.push({
            id: j,
            name: faker.name.findName(),
            email: faker.internet.email(),
            country: faker.address.country(),
            city: faker.address.city(),
            expenses: faker.finance.amount(),
            text: shuffleSentence(sentence),
            text2: faker.lorem.words(1)
        });
    }
    return data;
}

function shuffleSentence(words) {
    if (typeof words === 'string') return words;
    words = words || faker.lorem.words(8);
    var str = faker.helpers.shuffle(words).join(' ').trim();
    return str.charAt(0).toUpperCase() + str.slice(1);
}

imgToBase64('document.jpg', function(base64) {
    base64Img = base64;
});

// You could either use a function similar to this or pre convert an image with for example http://dopiaza.org/tools/datauri
// http://stackoverflow.com/questions/6150289/how-to-convert-image-into-base64-string-using-javascript
function imgToBase64(url, callback) {
    if (!window.FileReader) {
        callback(null);
        return;
    }
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'blob';
    xhr.onload = function() {
        var reader = new FileReader();
        reader.onloadend = function() {
            callback(reader.result.replace('text/xml', 'image/jpeg'));
        };
        reader.readAsDataURL(xhr.response);
    };
    xhr.open('GET', url);
    xhr.send();
}<|endoftext|>