<commit_before>'use strict';
/* Parser.js -- transforms keyboard input into tokens.
 + key_handler :: KeyboardEvent -> State|Object

 key_handler calls update synchronously, but if this someday hurts performance
 it could easily be converted to a requestAnimationFrame callback, or with
 more work, it could be sequestered into a Worker thread.
 */
const Parser=(logging=0)=>{
  const chord=[
    {code:'BracketLeft',type:'escape',mods:[2]},
    {code:'KeyG',type:'escape',mods:[2]},
    {code:'KeyD',type:'motion',mods:[2]},
    {code:'KeyU',type:'motion',mods:[2]},
    {code:'KeyF',type:'motion',mods:[2]},
    {code:'KeyB',type:'motion',mods:[2]},
    {code:'KeyH',type:'i_motion',mods:[2]},
    {code:'KeyJ',type:'i_motion',mods:[2]},
    {code:'KeyK',type:'i_motion',mods:[2]},
    {code:'KeyL',type:'i_motion',mods:[2]},
    {code:'KeyV',type:'visual',mods:[2]}
  ];

  const sequence=[/* NOTE -- these can't overlap other actions (including atoms), use sparingly. */
    {code:'fd',type:'escape',dt:200},
    {code:'cc',type:'phrase'},
    {code:'dd',type:'phrase'},
    {code:'yy',type:'phrase'},
    {code:'cs',type:'csurround'},
    {code:'ds',type:'dsurround'},
    {code:'ys',type:'ysurround'},/* NOTE -- this is a prefix of ysurround_line, AND is in the behavior tree. */
    {code:'yss',type:'ysurround_line'}
  ].map(x=>{x.code=[...x.code].reverse().join('');return x;});

  const atom=(()=>{/* {Char:[Type]} */
    let xs={
      ascii:'',
      bracket:'[{()}]',
      edit:'oOpPrxX~',
      insert:'aAiI',
      leader:' ',
      modifier:'ai',
      motion:'hjkl',
      mult_0:'123456789',
      mult_N:'0123456789',
      repeat:'.',
      search:'/?',
      seek:'fFtT',
      surround:'s',
      tag:' 0123456789=:-',
      tag_end:'/>',
      tag_start:'t',
      text_object:'0^$%{}()[]<>`"\'bBeEpwWG',
      undo:'u',
      verb:'cdy`',
      visual:'vV'
    };
    const range=(a,b,c=1)=>{let r=[];while(a<b){r.push(a);a+=c;}return r;};
    [['ascii',32,127,9],['tag',65,90],['tag',97,122]]
      .forEach(([o,x,y,...others])=>{xs[o]+=String.fromCharCode(...range(x,y+1).concat(others));});
    const less=(a,b)=>{let r=[];for(let i in a){if(!b.includes(a[i])){r.push(a[i]);}}return r;};
    xs.ascii_partial=less(xs.ascii,(xs.bracket+'t<>')).join('');
    let t={}; for(let i in xs){[...xs[i]].forEach(y=>t[y]?t[y].push(i):t[y]=[i]);};
    ['enter','escape','tab'].forEach(x=>{t[x[0].toUpperCase()+x.slice(1)]=[x];});
    ['Down','Left','Right','Up'].map(x=>t['Arrow'+x]=['arrow']);
    t.PageDown=t.PageUp=t.Home=t.End=['motion'];
    t.Delete=t.Backspace=['edit'];
    return t;
  })();

  const leaf=1, branch=2, nomatch=3;
  const lt=()=>({tab:leaf, ascii:leaf});/* TODO -- Leader Tree */
  const st=(n=0)=>{/* State Tree */
    const bt=({ascii_partial:leaf, bracket:leaf, tag_start:{get tag(){return this;}, tag_end:leaf}}),
          re=({enter:leaf, get ascii(){return this;}});
    return((x)=>{
      if(n===1){/* replace mult_0 with mult_N */
        delete x.mult_0; Object.defineProperty(x,'mult_N',{get:function(){return this;}});
      } return x;
    })({
      get mult_0(){return st(1);},
      get leader(){return lt();},
      tab:leaf,
      edit:leaf,
      arrow:leaf,
      insert:leaf,
      motion:leaf,
      repeat:leaf,
      text_object:leaf,
      undo:leaf,
      search:re,
      seek:{ascii:leaf},
      visual:leaf,
      verb:{
        modifier:{
          seek:{ascii:leaf},
          text_object:leaf},
        motion:leaf,
        phrase:leaf,
        csurround:{bracket:bt, tag_start:bt},
        dsurround:{bracket:leaf, tag_start:leaf},
        ysurround:{
          bracket:bt,
          modifier:{motion:bt, seek:{ascii:bt}, text_object:bt},
          motion:bt,
          seek:{ascii:bt},
          text_object:bt,
          ysurround_line:bt},
        text_object:leaf,
        seek:{ascii:leaf}}});
  };

  const chord_or_null=(n)=>{
    const m=n[0].mods; if(!m){return null;}
    const kc=n[0].chord, mods=['Alt','Control','Meta','Shift'];
    if(kc.every(x=>mods.reduce((a,b)=>a|x.startsWith(b)|0,0))){return ({ignore:1});}
    for(let {code:cc, mods:cm, type:ct} of chord){
      if(kc.includes(cc) && cm.some(y=>y===m)){return ({type:ct, len:kc.length});}
    } return null;
  };

  const sequence_or_null=(n)=>{
    const ns=n.map(x=>x.key).join(''), dts=n.map(x=>x.ts), snds=dts.slice(1),
          fast_enough=(a,b)=>!a || dts.slice(0,b.length-1).map((x,i)=>x-snds[i]).every(x=>a>x),
          lcp=(a,b)=>{let r=[];for(let i in b){if(a[i]===b[i]){r.push(a[i]);}else{break;}}return r.join('');};
    for(let {code:sr, dt:sd, type:st} of sequence){
      let cp=lcp(ns,sr);
      if(cp===sr && fast_enough(sd,sr)){return ({type:st, len:0});}
    } return null;
  };

  const atom_or_null=(n)=>{
    const types=atom[n[0].key]; if(!types){return null;}
    if(types.join()==='escape'){return ({type:'escape', len:0});}
    const m=n[0].mods,
          ns=Object.getOwnPropertyNames(stt);/* hmm... */
    for(let i in types){
      if((0===m || 8===m) && ns.includes(types[i])){return ({type:types[i], len:0});}
    } return null;
  };

  /* Input => (leaf|branch|nomatch) */
  const climb_tree=(a)=>{
    let r=stt[a]; if(r){
      vals.part.push(a);
      if(leaf===r){return leaf;}
      stt=r; return branch;
    } return nomatch;
  };

  const fns=[chord_or_null,sequence_or_null,atom_or_null],
        reset=()=>[st(),{keys:[],mods:[],part:[]},[]],
        R=(a,b)=>{let r={};if(2&b){r=vals;}if(1&b){[stt,vals,inq]=reset();}r.status=a;return r;};

  /* State Variables */
  let [stt,vals,inq]=reset();

  /* update -- given a new KeyboardEvent, what changes to the internal state? */
  const update=(input)=>{
    inq.unshift(input);
    let t=null; for(let fn of fns){
      if((t=fn(inq))){
        inq=inq.slice(t.len);
        if('escape'===t.type){return R('quit',1);}
        if(t.ignore){return R('ignore',0);}
        vals.keys.push(input.key);
        vals.mods.push(input.mods);
        t=climb_tree(t.type);
        if(nomatch===t){return R('error',1);}
        if(leaf===t){return R('done',3);}
        if(branch===t){return R('continue',2);}
      }
    } return R('error',1);
  };

  const KC=new Set();
  const key_handler=(a,b)=>{
    KC[b?'delete':'add'](a.code); if(b){return null;}
    const evt={key:a.key, code:a.code, ts:a.timeStamp|0,
               mods:['altKey','ctrlKey','metaKey','shiftKey'].reduce((x,y,z)=>x|((a[y]|0)<<z),0),
               chord:Array.from(KC)},
          ad={'KeyI':[10,5],'KeyR':[2,4]}[evt.code];/* allow default */
    if(ad && ad[navigator.platform==='MacIntel'|0]===evt.mods){return null;}
    a.preventDefault();
    return update(evt);
  };
  return ({key_handler});
};
<commit_msg>parseInt adds readability (and 1 extra byte)<commit_after>'use strict';
/* Parser.js -- transforms keyboard input into tokens.
 + key_handler :: KeyboardEvent -> State|Object

 key_handler calls update synchronously, but if this someday hurts performance
 it could easily be converted to a requestAnimationFrame callback, or with
 more work, it could be sequestered into a Worker thread.
 */
const Parser=(logging=0)=>{
  const chord=[
    {code:'BracketLeft',type:'escape',mods:[2]},
    {code:'KeyG',type:'escape',mods:[2]},
    {code:'KeyD',type:'motion',mods:[2]},
    {code:'KeyU',type:'motion',mods:[2]},
    {code:'KeyF',type:'motion',mods:[2]},
    {code:'KeyB',type:'motion',mods:[2]},
    {code:'KeyH',type:'i_motion',mods:[2]},
    {code:'KeyJ',type:'i_motion',mods:[2]},
    {code:'KeyK',type:'i_motion',mods:[2]},
    {code:'KeyL',type:'i_motion',mods:[2]},
    {code:'KeyV',type:'visual',mods:[2]}
  ];

  const sequence=[/* NOTE -- these can't overlap other actions (including atoms), use sparingly. */
    {code:'fd',type:'escape',dt:200},
    {code:'cc',type:'phrase'},
    {code:'dd',type:'phrase'},
    {code:'yy',type:'phrase'},
    {code:'cs',type:'csurround'},
    {code:'ds',type:'dsurround'},
    {code:'ys',type:'ysurround'},/* NOTE -- this is a prefix of ysurround_line, AND is in the behavior tree. */
    {code:'yss',type:'ysurround_line'}
  ].map(x=>{x.code=[...x.code].reverse().join('');return x;});

  const atom=(()=>{/* {Char:[Type]} */
    let xs={
      ascii:'',
      bracket:'[{()}]',
      edit:'oOpPrxX~',
      insert:'aAiI',
      leader:' ',
      modifier:'ai',
      motion:'hjkl',
      mult_0:'123456789',
      mult_N:'0123456789',
      repeat:'.',
      search:'/?',
      seek:'fFtT',
      surround:'s',
      tag:' 0123456789=:-',
      tag_end:'/>',
      tag_start:'t',
      text_object:'0^$%{}()[]<>`"\'bBeEpwWG',
      undo:'u',
      verb:'cdy`',
      visual:'vV'
    };
    const range=(a,b,c=1)=>{let r=[];while(a<b){r.push(a);a+=c;}return r;};
    [['ascii',32,127,9],['tag',65,90],['tag',97,122]]
      .forEach(([o,x,y,...others])=>{xs[o]+=String.fromCharCode(...range(x,y+1).concat(others));});
    const less=(a,b)=>{let r=[];for(let i in a){if(!b.includes(a[i])){r.push(a[i]);}}return r;};
    xs.ascii_partial=less(xs.ascii,(xs.bracket+'t<>')).join('');
    let t={}; for(let i in xs){[...xs[i]].forEach(y=>t[y]?t[y].push(i):t[y]=[i]);};
    ['enter','escape','tab'].forEach(x=>{t[x[0].toUpperCase()+x.slice(1)]=[x];});
    ['Down','Left','Right','Up'].map(x=>t['Arrow'+x]=['arrow']);
    t.PageDown=t.PageUp=t.Home=t.End=['motion'];
    t.Delete=t.Backspace=['edit'];
    return t;
  })();

  const leaf=1, branch=2, nomatch=3;
  const lt=()=>({tab:leaf, ascii:leaf});/* TODO -- Leader Tree */
  const st=(n=0)=>{/* State Tree */
    const bt=({ascii_partial:leaf, bracket:leaf, tag_start:{get tag(){return this;}, tag_end:leaf}}),
          re=({enter:leaf, get ascii(){return this;}});
    return((x)=>{
      if(n===1){/* replace mult_0 with mult_N */
        delete x.mult_0; Object.defineProperty(x,'mult_N',{get:function(){return this;}});
      } return x;
    })({
      get mult_0(){return st(1);},
      get leader(){return lt();},
      tab:leaf,
      edit:leaf,
      arrow:leaf,
      insert:leaf,
      motion:leaf,
      repeat:leaf,
      text_object:leaf,
      undo:leaf,
      search:re,
      seek:{ascii:leaf},
      visual:leaf,
      verb:{
        modifier:{
          seek:{ascii:leaf},
          text_object:leaf},
        motion:leaf,
        phrase:leaf,
        csurround:{bracket:bt, tag_start:bt},
        dsurround:{bracket:leaf, tag_start:leaf},
        ysurround:{
          bracket:bt,
          modifier:{motion:bt, seek:{ascii:bt}, text_object:bt},
          motion:bt,
          seek:{ascii:bt},
          text_object:bt,
          ysurround_line:bt},
        text_object:leaf,
        seek:{ascii:leaf}}});
  };

  const chord_or_null=(n)=>{
    const m=n[0].mods; if(!m){return null;}
    const kc=n[0].chord, mods=['Alt','Control','Meta','Shift'];
    if(kc.every(x=>mods.reduce((a,b)=>a|x.startsWith(b)|0,0))){return ({ignore:1});}
    for(let {code:cc, mods:cm, type:ct} of chord){
      if(kc.includes(cc) && cm.some(y=>y===m)){return ({type:ct, len:kc.length});}
    } return null;
  };

  const sequence_or_null=(n)=>{
    const ns=n.map(x=>x.key).join(''), dts=n.map(x=>x.ts), snds=dts.slice(1),
          fast_enough=(a,b)=>!a || dts.slice(0,b.length-1).map((x,i)=>x-snds[i]).every(x=>a>x),
          lcp=(a,b)=>{let r=[];for(let i in b){if(a[i]===b[i]){r.push(a[i]);}else{break;}}return r.join('');};
    for(let {code:sr, dt:sd, type:st} of sequence){
      let cp=lcp(ns,sr);
      if(cp===sr && fast_enough(sd,sr)){return ({type:st, len:0});}
    } return null;
  };

  const atom_or_null=(n)=>{
    const types=atom[n[0].key]; if(!types){return null;}
    if(types.join()==='escape'){return ({type:'escape', len:0});}
    const m=n[0].mods,
          ns=Object.getOwnPropertyNames(stt);/* hmm... */
    for(let i in types){
      if((0===m || 8===m) && ns.includes(types[i])){return ({type:types[i], len:0});}
    } return null;
  };

  /* Input => (leaf|branch|nomatch) */
  const climb_tree=(a)=>{
    let r=stt[a]; if(r){
      vals.part.push(a);
      if(leaf===r){return leaf;}
      stt=r; return branch;
    } return nomatch;
  };

  const fns=[chord_or_null,sequence_or_null,atom_or_null],
        reset=()=>[st(),{keys:[],mods:[],part:[]},[]],
        R=(a,b)=>{let r={};if(2&b){r=vals;}if(1&b){[stt,vals,inq]=reset();}r.status=a;return r;};

  /* State Variables */
  let [stt,vals,inq]=reset();

  /* update -- given a new KeyboardEvent, what changes to the internal state? */
  const update=(input)=>{
    inq.unshift(input);
    let t=null; for(let fn of fns){
      if((t=fn(inq))){
        inq=inq.slice(t.len);
        if('escape'===t.type){return R('quit',1);}
        if(t.ignore){return R('ignore',0);}
        vals.keys.push(input.key);
        vals.mods.push(input.mods);
        t=climb_tree(t.type);
        if(nomatch===t){return R('error',1);}
        if(leaf===t){return R('done',3);}
        if(branch===t){return R('continue',2);}
      }
    } return R('error',1);
  };

  const KC=new Set();
  const key_handler=(a,b)=>{
    KC[b?'delete':'add'](a.code); if(b){return null;}
    const evt={key:a.key, code:a.code, ts:a.timeStamp|0,
               mods:parseInt(['shiftKey','metaKey','ctrlKey','altKey'].map(x=>a[x]|0).join(''),2),
               chord:Array.from(KC)},
          ad={'KeyI':[10,5],'KeyR':[2,4]}[evt.code];/* allow default */
    if(ad && ad[navigator.platform==='MacIntel'|0]===evt.mods){return null;}
    a.preventDefault();
    return update(evt);
  };
  return ({key_handler});
};
<|endoftext|>


<commit_before>define('isr/player', ['jquery', 'isr', 'isr/config'], function($, Game, Config) {
   console.log('director')
   console.log(Game.director)
   console.log(Game.director.currentScene)
   var $activeScene;
   var $activeCharacter;

   // current player position
   var playerTilePos = {
      'x' : 0,
      'y' : 0
   };
   var startTime = 0;
   // var to indicate if character is currently moving
   var moving = false;

   Game.director.on('scene:change', function(scene) {
      console.log('switched scene to ' +scene);
      $activeScene = $('#' + scene);
      console.log($activeScene)
      $activeCharacter = $activeScene.find('#character');
      console.log($activeCharacter)
   });

   $('body').keyup(function(e) {
      console.log('Player movement listener reporting to duty');
      var charPos = $activeCharacter.offset();
console.log(charPos)
      var up = ~~((e.keyCode === 87) || (e.keyCode === 38));
      // W || Arrow up
      var down = ~~((e.keyCode === 83) || (e.keyCode === 40));
      // S || Arrow down
      var left = ~~((e.keyCode === 65) || (e.keyCode === 37));
      // A || Arrow left
      var right = ~~((e.keyCode === 68) || (e.keyCode === 39));
      // D || Arrow right

      var direction;

      if (up) {
         direction = 'up';
      } else if (down) {
         direction = 'down';
      } else if (left) {
         direction = 'left';
      } else if (right) {
         direction = 'right';
      }

      var newPos = {
         left : charPos.left,
         top : charPos.top
      };

      if (!moving && direction) {
        move(direction);
      }
   });

      /**
    * Function to check if movement in desired direction is possible
    * @param {Object} direction
    */
   var checkMove = function(direction) {
      var tileToMove = {
         'x' : playerTilePos.x,
         'y' : playerTilePos.y
      };
      switch(direction) {
         case 'left':
            if (playerTilePos.x === 0) {
               return false;
            }
            tileToMove.x -= 1;
            break;
         case 'right':
            if (playerTilePos.x === (Config.tilesLimit.x - 1)) {
               return false;
            }
            tileToMove.x += 1;
            break;
         case 'up':
            if (playerTilePos.y === 0) {
               return {};
            }
            tileToMove.y -= 1;
            break;
         case 'down':
            if (playerTilePos.y === (Config.tilesLimit.y - 1)) {
               return false;
            }
            tileToMove.y += 1;
            break;
      }

      // check if next tile is accessible
      if ($activeScene.find('#x' + tileToMove.x + '-y' + tileToMove.y).hasClass('notAccessible')) {
         return {};
      }
      return tileToMove;
   };

   /**
    * Function to check if there is sth on the current tile and pick it up
    */
   var checkAndPickUp = function() {
      $activeScene.find('#x' + playerTilePos.x + '-y' + playerTilePos.y).find('.item').each(function(index) {

         var itemName = $(this).attr('class').split(' ');
         //Inventory.addItem(itemName[itemName.length - 1]);
         //grunt
         //Config.sound.play('happy');
         $(this).remove();
      });
   };
   /**
    * Function to move player to the next tile from his position
    * @param {Object} direction
    * @param {Object} callBack
    */
   var move = function(direction, callBack) {
      if (direction === '') {
         return;
      }
      var targetTiles = checkMove(direction);
      console.log(targetTiles)
      if (!moving && !$.isEmptyObject(targetTiles)) {
         var movOptions;
         switch (direction) {
            case 'up':
               movOptions = {
                  'top' : '-=' + Config.tile.width
               };
               break;
            case 'down':
               movOptions = {
                  'top' : '+=' + Config.tile.width
               };
               break;
            case 'left':
               movOptions = {
                  'left' : '-=' + Config.tile.width
               };
               break;
            case 'right':
               movOptions = {
                  'left' : '+=' + Config.tile.width
               };
               break;
         }
         moving = true;
         playerTilePos = targetTiles;

         $activeCharacter.animate(movOptions, 'slow', function() {
            moving = false;
            if (callBack) {
               callBack();
            }
         });
      } else {
         return;
      }
   };
}); <commit_msg>added player facing direction and interaction on space key<commit_after>define('isr/player', ['jquery', 'isr', 'isr/config'], function($, Game, Config) {
   console.log('director')
   console.log(Game.director)
   console.log(Game.director.currentScene)
   var $activeScene;
   var $activeCharacter;

   // current player position
   var playerTilePos = {
      'x' : 0,
      'y' : 0,
      'facing' : 'up'
   };
   var startTime = 0;
   // var to indicate if character is currently moving
   var moving = false;

   Game.director.on('scene:change', function(scene) {
      console.log('switched scene to ' +scene);
      $activeScene = $('#' + scene);
      console.log($activeScene)
      $activeCharacter = $activeScene.find('#character');
      console.log($activeCharacter)
   });

   $('body').keyup(function(e) {
      console.log('Player movement listener reporting to duty');
      var charPos = $activeCharacter.offset();
console.log(charPos)
      // W || Arrow up
      var up = ~~((e.keyCode === 87) || (e.keyCode === 38));
      // S || Arrow down
      var down = ~~((e.keyCode === 83) || (e.keyCode === 40));
      // A || Arrow left
      var left = ~~((e.keyCode === 65) || (e.keyCode === 37));
      // D || Arrow right
      var right = ~~((e.keyCode === 68) || (e.keyCode === 39));
      // space for interaction
      var space = ~~(e.keyCode === 32);
      var direction;

      if (up) {
         direction = 'up';
      } else if (down) {
         direction = 'down';
      } else if (left) {
         direction = 'left';
      } else if (right) {
         direction = 'right';
      }

      /*var newPos = {
         left : charPos.left,
         top : charPos.top
      };*/

      // move player
      if (!moving && direction) {
        move(direction);
      }

      if (space) {
         doAction();
      }
      e.stopPropagation();
      e.preventDefault();
      e.stopImmediatePropagation();
      return false;
   });

      /**
    * Function to check if movement in desired direction is possible
    * @param {Object} direction
    */
   var checkMove = function(direction) {
      var tileToMove = {
         'x' : playerTilePos.x,
         'y' : playerTilePos.y,
         'facing' : direction
      };
      switch(direction) {
         case 'left':
            if (playerTilePos.x === 0) {
               return false;
            }
            tileToMove.x -= 1;
            break;
         case 'right':
            if (playerTilePos.x === (Config.tilesLimit.x - 1)) {
               return false;
            }
            tileToMove.x += 1;
            break;
         case 'up':
            if (playerTilePos.y === 0) {
               return {};
            }
            tileToMove.y -= 1;
            break;
         case 'down':
            if (playerTilePos.y === (Config.tilesLimit.y - 1)) {
               return false;
            }
            tileToMove.y += 1;
            break;
      }

      // check if next tile is accessible
      if ($activeScene.find('#x' + tileToMove.x + '-y' + tileToMove.y).hasClass('notAccessible')) {
         return {};
      }
      return tileToMove;
   };

   /**
    * Function to do stuff like fight or talk
    */
   var doAction = function() {
      // first check direction
      var targetTile = {
         x : playerTilePos.x,
         y : playerTilePos.y
      };
      switch(playerTilePos.facing) {
         case 'up':
            targetTile.y += 1;
         break;
         case 'down':
            targetTile.y -= 1;
         break;
         case 'left':
            targetTile.x -= 1;
         break;
         case 'right':
            targetTile.y += 1;
         break;
      }
      // check if on there is sth on the tile the player is facing to interact with
      var interactableStuff = $activeScene.find('#x' + targetTile.x + '-y' + targetTile.y + ' .interactable');
      interactableStuff.each(function(index) {
         if ($(this).hasClass('attackable')) {
            // TODO do fancy animation
         } else if ($(this).hasClass('talkable')) {
            alert('Your are talking to someone');
         }
      });
      if (interactableStuff.length === 0) {
         //TODO add fancy sword swing into empty air
         alert('You successfully killed empty air');
      }

   };
   /**
    * Function to move player to the next tile from his position
    * @param {Object} direction
    * @param {Object} callBack
    */
   var move = function(direction, callBack) {
      if (direction === '') {
         return;
      }
      var targetTiles = checkMove(direction);
      console.log(targetTiles)
      if (!moving && !$.isEmptyObject(targetTiles)) {
         var movOptions;
         switch (direction) {
            case 'up':
               movOptions = {
                  'top' : '-=' + Config.tile.width
               };
               break;
            case 'down':
               movOptions = {
                  'top' : '+=' + Config.tile.width
               };
               break;
            case 'left':
               movOptions = {
                  'left' : '-=' + Config.tile.width
               };
               break;
            case 'right':
               movOptions = {
                  'left' : '+=' + Config.tile.width
               };
               break;
         }
         moving = true;
         playerTilePos = targetTiles;

         $activeCharacter.animate(movOptions, 'slow', function() {
            // TODO add player rotation in the right direction
            moving = false;
            if (callBack) {
               callBack();
            }
         });
      } else {
         // TODO add player rotation in the right direction
         playerTilePos.facing = direction;
         return;
      }
   };
}); <|endoftext|>


<commit_before>(function()
{
  var getHandlers = function(object, type)
  {
    var events = object.__events || (object.__events = {});
    return events[type] || (events[type] = []);
  };

  var slice = Array.prototype.slice;

  /**
   * Generic event interface for Core classes.
   */
  core.Class("core.event.MEvent",
  {
    members :
    {
      /**
       * {Boolean} Registers a listener of the given @type {String} of event to
       * execute the @callback {Function} in the given @context {Object?}. Returns
       * whether adding the listener was successful.
       */
      addListener : function(type, callback, context)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type!");
          core.Assert.isNotEmpty(type, "Invalid event type!");
          core.Assert.isType(callback, "Function", "Invalid event callback!");

          if (context != null) {
            core.Assert.isType(context, "Object", "Invalid execution context!");
          }
        }

        // Simplify internal storage using Function.bind()
        if (context) {
          callback = core.util.Function.bind(callback, context);
        }

        var handlers = getHandlers(this, type);

        if (handlers.indexOf(callback) != -1) {
          return false;
        }

        handlers.push(callback);
        return true;
      },

      /**
       * {Boolean} Like {#addListener} but executes the @callback {Function} for the event @type {String}
       * only on the first event and then unregisters the @callback automatically.
       * Supports @context {Object?} for defining the execution context as well. Returns
       * whether adding the listener was successful.
       */
      addListenerOnce : function(type, callback, context)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type!");
          core.Assert.isNotEmpty(type, "Invalid event type!");
          core.Assert.isType(callback, "Function", "Invalid event callback!");

          if (context != null) {
            core.Assert.isType(context, "Object", "Invalid execution context!");
          }
        }

        var self = this;

        if (self.hasListener(type, callback, context)) {
          return false;
        }

        var wrapper = function()
        {
          self.removeListener(type, wrapper);
          return callback.apply(context||self, arguments);
        };

        return this.addListener(type, wrapper);
      },

      /**
       * {Boolean} Removes a listener of the given @type {String} of event to
       * execute the @callback {Function} in the given @context {Object?}. Returns
       * whether removing the listener was successful.
       */
      removeListener : function(type, callback, context)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type!");
          core.Assert.isNotEmpty(type, "Invalid event type!");
          core.Assert.isType(callback, "Function", "Invalid event callback!");

          if (context != null) {
            core.Assert.isType(context, "Object", "Invalid execution context!");
          }
        }

        // Simplify internal storage using Function.bind()
        if (context) {
          callback = core.util.Function.bind(callback, context);
        }

        var handlers = getHandlers(this, type);

        var position = handlers.indexOf(callback);
        if (position == -1) {
          return false;
        }

        handlers.splice(position, 1);
        return true;
      },

      /**
       * Removes all listeners from this object with optional
       * support for only removing events of the given @type {String?}.
       */
      removeAllListeners : function(type)
      {
        if (jasy.Env.isSet("debug"))
        {
          if (type != null)
          {
            core.Assert.isType(type, "String", "Invalid event type!");
            core.Assert.isNotEmpty(type, "Invalid event type!");
          }
        }

        if (type != null) {
          getHandlers(this, type).length = 0;
        } else {
          this.__events = {};
        }
      },

      /**
       * {Boolean} Returns whether the given event @type {String} has any listeners.
       * The method could optionally figure out whether a specific
       * @callback {Function?} (with optional @context {Object?}) is
       * registered already.
       */
      hasListener : function(type, callback, context)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type!");
          core.Assert.isNotEmpty(type, "Invalid event type!");
          core.Assert.isType(callback, "Function", "Invalid event callback!");

          if (context != null) {
            core.Assert.isType(context, "Object", "Invalid execution context!");
          }
        }

        var handlers = getHandlers(this, type);

        // Short path for callback-less usage.
        if (!callback) {
          return handlers.length > 0;
        }

        // Simplify internal storage using Function.bind()
        if (context) {
          callback = core.util.Function.bind(callback, context);
        }

        return handlers.indexOf(callback) != -1;
      },

      /**
       * {Boolean} Fires the given event @type {String} with
       * optional @varargs {var ... ?} which are passed to every
       * listener function as arguments. Returns whether any
       * listeners were processed successfully.
       */
      fireEvent : function(type, varargs)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type to fire!");
          core.Assert.isNotEmpty(type, "Invalid event type to fire!");
        }

        var self = this;
        var handlers = slice.call(getHandlers(self, type));
        var length = handlers.length;

        if (length)
        {
          var hasArgs = arguments.length > 1;
          if (hasArgs) {
            var args = slice.call(arguments, 1);
          }

          for (var i = 0; i < length; ++i) {
            hasArgs ? handlers[i].apply(self, args) : handlers[i].call(this);
          }

          return true;
        }

        return false;
      }
    }

  });

})();
<commit_msg>Fixed assertions<commit_after>(function()
{
  var getHandlers = function(object, type)
  {
    var events = object.__events || (object.__events = {});
    return events[type] || (events[type] = []);
  };

  var slice = Array.prototype.slice;

  /**
   * Generic event interface for Core classes.
   */
  core.Class("core.event.MEvent",
  {
    members :
    {
      /**
       * {Boolean} Registers a listener of the given @type {String} of event to
       * execute the @callback {Function} in the given @context {Object?}. Returns
       * whether adding the listener was successful.
       */
      addListener : function(type, callback, context)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type - non string!");
          core.Assert.isNotEmpty(type, "Invalid event type - empty string!");
          core.Assert.isType(callback, "Function", "Invalid event callback!");

          if (context != null) {
            core.Assert.isType(context, "Object", "Invalid execution context!");
          }
        }

        // Simplify internal storage using Function.bind()
        if (context) {
          callback = core.util.Function.bind(callback, context);
        }

        var handlers = getHandlers(this, type);

        if (handlers.indexOf(callback) != -1) {
          return false;
        }

        handlers.push(callback);
        return true;
      },

      /**
       * {Boolean} Like {#addListener} but executes the @callback {Function} for the event @type {String}
       * only on the first event and then unregisters the @callback automatically.
       * Supports @context {Object?} for defining the execution context as well. Returns
       * whether adding the listener was successful.
       */
      addListenerOnce : function(type, callback, context)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type!");
          core.Assert.isNotEmpty(type, "Invalid event type!");
          core.Assert.isType(callback, "Function", "Invalid event callback!");

          if (context != null) {
            core.Assert.isType(context, "Object", "Invalid execution context!");
          }
        }

        var self = this;

        if (self.hasListener(type, callback, context)) {
          return false;
        }

        var wrapper = function()
        {
          self.removeListener(type, wrapper);
          return callback.apply(context||self, arguments);
        };

        return this.addListener(type, wrapper);
      },

      /**
       * {Boolean} Removes a listener of the given @type {String} of event to
       * execute the @callback {Function} in the given @context {Object?}. Returns
       * whether removing the listener was successful.
       */
      removeListener : function(type, callback, context)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type!");
          core.Assert.isNotEmpty(type, "Invalid event type!");
          core.Assert.isType(callback, "Function", "Invalid event callback!");

          if (context != null) {
            core.Assert.isType(context, "Object", "Invalid execution context!");
          }
        }

        // Simplify internal storage using Function.bind()
        if (context) {
          callback = core.util.Function.bind(callback, context);
        }

        var handlers = getHandlers(this, type);

        var position = handlers.indexOf(callback);
        if (position == -1) {
          return false;
        }

        handlers.splice(position, 1);
        return true;
      },

      /**
       * Removes all listeners from this object with optional
       * support for only removing events of the given @type {String?}.
       */
      removeAllListeners : function(type)
      {
        if (jasy.Env.isSet("debug"))
        {
          if (type != null)
          {
            core.Assert.isType(type, "String", "Invalid event type!");
            core.Assert.isNotEmpty(type, "Invalid event type!");
          }
        }

        if (type != null) {
          getHandlers(this, type).length = 0;
        } else {
          this.__events = {};
        }
      },

      /**
       * {Boolean} Returns whether the given event @type {String} has any listeners.
       * The method could optionally figure out whether a specific
       * @callback {Function?} (with optional @context {Object?}) is
       * registered already.
       */
      hasListener : function(type, callback, context)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type!");
          core.Assert.isNotEmpty(type, "Invalid event type!");

          if (callback != null)
          {
            core.Assert.isType(callback, "Function", "Invalid event callback!");

            if (context != null) {
              core.Assert.isType(context, "Object", "Invalid execution context!");
            }
          }
        }

        var handlers = getHandlers(this, type);

        // Short path for callback-less usage.
        if (!callback) {
          return handlers.length > 0;
        }

        // Simplify internal storage using Function.bind()
        if (context) {
          callback = core.util.Function.bind(callback, context);
        }

        return handlers.indexOf(callback) != -1;
      },

      /**
       * {Boolean} Fires the given event @type {String} with
       * optional @varargs {var ... ?} which are passed to every
       * listener function as arguments. Returns whether any
       * listeners were processed successfully.
       */
      fireEvent : function(type, varargs)
      {
        if (jasy.Env.isSet("debug"))
        {
          core.Assert.isType(type, "String", "Invalid event type to fire!");
          core.Assert.isNotEmpty(type, "Invalid event type to fire!");
        }

        var self = this;
        var handlers = slice.call(getHandlers(self, type));
        var length = handlers.length;

        if (length)
        {
          var hasArgs = arguments.length > 1;
          if (hasArgs) {
            var args = slice.call(arguments, 1);
          }

          for (var i = 0; i < length; ++i) {
            hasArgs ? handlers[i].apply(self, args) : handlers[i].call(this);
          }

          return true;
        }

        return false;
      }
    }

  });

})();
<|endoftext|>


<commit_before>import { window, document } from 'ssr-window';

const Device = (function Device() {
  const platform = window.navigator.platform;
  const ua = window.navigator.userAgent;

  const device = {
    ios: false,
    android: false,
    androidChrome: false,
    desktop: false,
    windowsPhone: false,
    iphone: false,
    iphoneX: false,
    ipod: false,
    ipad: false,
    edge: false,
    ie: false,
    firefox: false,
    macos: false,
    windows: false,
    cordova: !!(window.cordova || window.phonegap),
    phonegap: !!(window.cordova || window.phonegap),
    electron: false,
  };

  const screenWidth = window.screen.width;
  const screenHeight = window.screen.height;

  const windowsPhone = ua.match(/(Windows Phone);?[\s\/]+([\d.]+)?/); // eslint-disable-line
  const android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); // eslint-disable-line
  const ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
  const ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
  const iphone = !ipad && ua.match(/(iPhone\sOS|iOS)\s([\d_]+)/);
  const iphoneX = iphone && (
    (screenWidth === 375 && screenHeight === 812) // X/XS
    || (screenWidth === 414 && screenHeight === 896) // XR / XS Max
  );
  const ie = ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0;
  const edge = ua.indexOf('Edge/') >= 0;
  const firefox = ua.indexOf('Gecko/') >= 0 && ua.indexOf('Firefox/') >= 0;
  const macos = platform === 'MacIntel';
  const windows = platform === 'Win32';
  const electron = ua.toLowerCase().indexOf('electron') >= 0;

  device.ie = ie;
  device.edge = edge;
  device.firefox = firefox;

  // Windows
  if (windowsPhone) {
    device.os = 'windowsPhone';
    device.osVersion = windowsPhone[2];
    device.windowsPhone = true;
  }
  // Android
  if (android && !windows) {
    device.os = 'android';
    device.osVersion = android[2];
    device.android = true;
    device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0;
  }
  if (ipad || iphone || ipod) {
    device.os = 'ios';
    device.ios = true;
  }
  // iOS
  if (iphone && !ipod) {
    device.osVersion = iphone[2].replace(/_/g, '.');
    device.iphone = true;
    device.iphoneX = iphoneX;
  }
  if (ipad) {
    device.osVersion = ipad[2].replace(/_/g, '.');
    device.ipad = true;
  }
  if (ipod) {
    device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
    device.ipod = true;
  }
  // iOS 8+ changed UA
  if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) {
    if (device.osVersion.split('.')[0] === '10') {
      device.osVersion = ua.toLowerCase().split('version/')[1].split(' ')[0];
    }
  }

  // Webview
  device.webView = !!((iphone || ipad || ipod) && (ua.match(/.*AppleWebKit(?!.*Safari)/i) || window.navigator.standalone))
    || (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches);
  device.webview = device.webView;
  device.standalone = device.webView;

  // Desktop
  device.desktop = !(device.ios || device.android || device.windowsPhone) || electron;
  if (device.desktop) {
    device.electron = electron;
    device.macos = macos;
    device.windows = windows;
  }

  // Meta statusbar
  const metaStatusbar = document.querySelector('meta[name="apple-mobile-web-app-status-bar-style"]');

  // Check for status bar and fullscreen app mode
  device.needsStatusbarOverlay = function needsStatusbarOverlay() {
    if (device.desktop) return false;
    if (device.standalone && device.ios && metaStatusbar && metaStatusbar.content === 'black-translucent') {
      return true;
    }
    if ((device.webView || (device.android && device.cordova)) && (window.innerWidth * window.innerHeight === window.screen.width * window.screen.height)) {
      if (device.iphoneX && (window.orientation === 90 || window.orientation === -90)) {
        return false;
      }
      return true;
    }
    return false;
  };
  device.statusbar = device.needsStatusbarOverlay();

  // Pixel Ratio
  device.pixelRatio = window.devicePixelRatio || 1;

  // Color Scheme
  const DARK = '(prefers-color-scheme: dark)';
  const LIGHT = '(prefers-color-scheme: light)';
  device.prefersColorScheme = function prefersColorTheme() {
    let theme;
    if (window.matchMedia && window.matchMedia(LIGHT).matches) {
      theme = 'light';
    }
    if (window.matchMedia && window.matchMedia(DARK).matches) {
      theme = 'dark';
    }
    return theme;
  };

  // Export object
  return device;
}());

export default Device;
<commit_msg>Core: Device - fix iOS/iPad detection for iPadOs 13 desktop mode<commit_after>import { window, document } from 'ssr-window';
import Support from './support';

const Device = (function Device() {
  const platform = window.navigator.platform;
  const ua = window.navigator.userAgent;

  const device = {
    ios: false,
    android: false,
    androidChrome: false,
    desktop: false,
    windowsPhone: false,
    iphone: false,
    iphoneX: false,
    ipod: false,
    ipad: false,
    edge: false,
    ie: false,
    firefox: false,
    macos: false,
    windows: false,
    cordova: !!(window.cordova || window.phonegap),
    phonegap: !!(window.cordova || window.phonegap),
    electron: false,
  };

  const screenWidth = window.screen.width;
  const screenHeight = window.screen.height;

  const windowsPhone = ua.match(/(Windows Phone);?[\s\/]+([\d.]+)?/); // eslint-disable-line
  const android = ua.match(/(Android);?[\s\/]+([\d.]+)?/); // eslint-disable-line
  let ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
  const ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
  const iphone = !ipad && ua.match(/(iPhone\sOS|iOS)\s([\d_]+)/);
  const iphoneX = iphone && (
    (screenWidth === 375 && screenHeight === 812) // X/XS
    || (screenWidth === 414 && screenHeight === 896) // XR / XS Max
  );
  const ie = ua.indexOf('MSIE ') >= 0 || ua.indexOf('Trident/') >= 0;
  const edge = ua.indexOf('Edge/') >= 0;
  const firefox = ua.indexOf('Gecko/') >= 0 && ua.indexOf('Firefox/') >= 0;
  const windows = platform === 'Win32';
  const electron = ua.toLowerCase().indexOf('electron') >= 0;
  let macos = platform === 'MacIntel';

  // iPadOs 13 fix
  if (!ipad
    && macos
    && Support.touch
    && (
      (screenWidth === 1024 && screenHeight === 1366)
      || (screenWidth === 768 && screenHeight === 1024)
    )
  ) {
    ipad = ua.match(/(Version)\/([\d.]+)/);
    macos = false;
  }

  device.ie = ie;
  device.edge = edge;
  device.firefox = firefox;

  // Windows
  if (windowsPhone) {
    device.os = 'windowsPhone';
    device.osVersion = windowsPhone[2];
    device.windowsPhone = true;
  }
  // Android
  if (android && !windows) {
    device.os = 'android';
    device.osVersion = android[2];
    device.android = true;
    device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0;
  }
  if (ipad || iphone || ipod) {
    device.os = 'ios';
    device.ios = true;
  }
  // iOS
  if (iphone && !ipod) {
    device.osVersion = iphone[2].replace(/_/g, '.');
    device.iphone = true;
    device.iphoneX = iphoneX;
  }
  if (ipad) {
    device.osVersion = ipad[2].replace(/_/g, '.');
    device.ipad = true;
  }
  if (ipod) {
    device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
    device.ipod = true;
  }
  // iOS 8+ changed UA
  if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) {
    if (device.osVersion.split('.')[0] === '10') {
      device.osVersion = ua.toLowerCase().split('version/')[1].split(' ')[0];
    }
  }

  // Webview
  device.webView = !!((iphone || ipad || ipod) && (ua.match(/.*AppleWebKit(?!.*Safari)/i) || window.navigator.standalone))
    || (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches);
  device.webview = device.webView;
  device.standalone = device.webView;

  // Desktop
  device.desktop = !(device.ios || device.android || device.windowsPhone) || electron;
  if (device.desktop) {
    device.electron = electron;
    device.macos = macos;
    device.windows = windows;
  }

  // Meta statusbar
  const metaStatusbar = document.querySelector('meta[name="apple-mobile-web-app-status-bar-style"]');

  // Check for status bar and fullscreen app mode
  device.needsStatusbarOverlay = function needsStatusbarOverlay() {
    if (device.desktop) return false;
    if (device.standalone && device.ios && metaStatusbar && metaStatusbar.content === 'black-translucent') {
      return true;
    }
    if ((device.webView || (device.android && device.cordova)) && (window.innerWidth * window.innerHeight === window.screen.width * window.screen.height)) {
      if (device.iphoneX && (window.orientation === 90 || window.orientation === -90)) {
        return false;
      }
      return true;
    }
    return false;
  };
  device.statusbar = device.needsStatusbarOverlay();

  // Pixel Ratio
  device.pixelRatio = window.devicePixelRatio || 1;

  // Color Scheme
  const DARK = '(prefers-color-scheme: dark)';
  const LIGHT = '(prefers-color-scheme: light)';
  device.prefersColorScheme = function prefersColorTheme() {
    let theme;
    if (window.matchMedia && window.matchMedia(LIGHT).matches) {
      theme = 'light';
    }
    if (window.matchMedia && window.matchMedia(DARK).matches) {
      theme = 'dark';
    }
    return theme;
  };

  // Export object
  return device;
}());

export default Device;
<|endoftext|>


<commit_before>import { isArray, isPrimitive } from '../util/index'
import VNode from './vnode'

export function flatten (children) {
  if (isArray(children)) {
    let res = []
    for (let i = 0, l = children.length; i < l; i++) {
      let c = children[i]
      // flatten nested
      if (isArray(c)) {
        res.push.apply(res, flatten(c))
      } else if (isPrimitive(c)) {
        // convert primitive to vnode
        res.push(VNode(undefined, undefined, undefined, c))
      } else if (c) {
        res.push(c)
      }
    }
    return res
  } else if (children) {
    return [children]
  }
}

export function updateListeners (on, oldOn, add) {
  let name, cur, old, event, capture
  for (name in on) {
    cur = on[name]
    old = oldOn[name]
    if (old === undefined) {
      capture = name.charAt(0) === '!'
      event = capture ? name.slice(1) : name
      if (isArray(cur)) {
        add(event, arrInvoker(cur), capture)
      } else {
        cur = { fn: cur }
        on[name] = cur
        add(event, fnInvoker(cur), capture)
      }
    } else if (isArray(old)) {
      old.length = cur.length
      for (let i = 0; i < old.length; i++) old[i] = cur[i]
      on[name] = old
    } else {
      old.fn = cur
      on[name] = old
    }
  }
}

function arrInvoker (arr) {
  return function (ev) {
    for (let i = 0; i < arr.length; i++) {
      arr[i](ev)
    }
  }
}

function fnInvoker (o) {
  return function (ev) { o.fn(ev) }
}
<commit_msg>fix hyperscript direct string as children<commit_after>import { isArray, isPrimitive } from '../util/index'
import VNode from './vnode'

export function flatten (children) {
  if (typeof children === 'string') {
    return [VNode(undefined, undefined, undefined, children)]
  }
  if (isArray(children)) {
    let res = []
    for (let i = 0, l = children.length; i < l; i++) {
      let c = children[i]
      // flatten nested
      if (isArray(c)) {
        res.push.apply(res, flatten(c))
      } else if (isPrimitive(c)) {
        // convert primitive to vnode
        res.push(VNode(undefined, undefined, undefined, c))
      } else if (c) {
        res.push(c)
      }
    }
    return res
  }
}

export function updateListeners (on, oldOn, add) {
  let name, cur, old, event, capture
  for (name in on) {
    cur = on[name]
    old = oldOn[name]
    if (old === undefined) {
      capture = name.charAt(0) === '!'
      event = capture ? name.slice(1) : name
      if (isArray(cur)) {
        add(event, arrInvoker(cur), capture)
      } else {
        cur = { fn: cur }
        on[name] = cur
        add(event, fnInvoker(cur), capture)
      }
    } else if (isArray(old)) {
      old.length = cur.length
      for (let i = 0; i < old.length; i++) old[i] = cur[i]
      on[name] = old
    } else {
      old.fn = cur
      on[name] = old
    }
  }
}

function arrInvoker (arr) {
  return function (ev) {
    for (let i = 0; i < arr.length; i++) {
      arr[i](ev)
    }
  }
}

function fnInvoker (o) {
  return function (ev) { o.fn(ev) }
}
<|endoftext|>


<commit_before>var registerElement = require('../vr-register-element').registerElement;

var TWEEN = require('tween.js');
var VRNode = require('./vr-node');
var utils = require('../vr-utils');

var defaults = {
  attribute: 'rotation',
  begin: '0',
  dur: 1000,
  easing: 'ease',
  direction: 'normal',
  fill: 'none',
  from: undefined,
  repeat: 0,
  to: undefined
};

var easingFunctions = {
  'ease': TWEEN.Easing.Cubic.InOut,
  'linear': TWEEN.Easing.Linear.None,
  'ease-in': TWEEN.Easing.Cubic.In,
  'ease-out': TWEEN.Easing.Cubic.Out,
  'ease-in-out': TWEEN.Easing.Cubic.InOut
};

module.exports = registerElement(
  'vr-animation', {
    prototype: Object.create(
      VRNode.prototype, {
        attachedCallback: {
          value: function () {
            this.el = this.parentNode;
            // preemptive binding to attach/dettach event listeners (see update method)
            this.bindMethods();
            this.applyMixin();
            this.load();
          },
          writable: window.debug
        },

        bindMethods: {
          value: function () {
            this.start = this.start.bind(this);
            this.stop = this.stop.bind(this);
            this.onStateAdded = this.onStateAdded.bind(this);
            this.onStateRemoved = this.onStateRemoved.bind(this);
          },
          writable: window.debug
        },

        attributeChangedCallback: {
          value: function () {
            this.stop();
            this.applyMixin();
          },
          writable: window.debug
        },

        update: {
          value: function () {
            var data = this.data;
            var begin = data.begin;
            // begin is an event name
            // Cancel previous event listeners
            this.removeEventListeners(this.evt);
            this.addEventListeners(begin);
            // Store new event name
            this.evt = begin;
            // If begin is a number we start the animation right away
            if (!isNaN(begin)) {
              this.stop();
              this.start();
              return;
            }
          }
        },

        addEventListeners: {
          value: function (evt) {
            var el = this.el;
            el.addEventListener(evt, this.start);
            el.addEventListener('stateadded', this.onStateAdded);
            el.addEventListener('stateremoved', this.onStateRemoved);
          },
          writable: window.debug
        },

        removeEventListeners: {
          value: function (evt) {
            var el = this.el;
            el.removeEventListener(evt, this.start);
            el.removeEventListener('stateadded', this.onStateAdded);
            el.removeEventListener('stateremoved', this.onStateRemoved);
          },
          writable: window.debug
        },

        onStateAdded: {
          value: function (evt) {
            if (evt.detail.state === this.data.begin) {
              this.start();
            }
          },
          writable: true
        },

        onStateRemoved: {
          value: function (evt) {
            if (evt.detail.state === this.data.begin) {
              this.stop();
            }
          },
          writable: true
        },

        init: {
          value: function () {
            // Stop previous tween
            var data = this.data;
            var repeat = data.repeat === 'indefinite' ? Infinity : 0;
            var el = this.el;
            var attribute = data.attribute;
            var current = el.getComputedAttribute(attribute);
            var from = data.from ? utils.parseCoordinate(data.from) : current;
            var tween = this.tween;
            var begin = parseInt(data.begin, 10);
            var to = utils.parseCoordinate(data.to);
            var easing = easingFunctions[data.easing];
            var fill = data.fill;
            var count = this.count;
            if (count === undefined) {
              this.count = repeat !== Infinity ? parseInt(data.repeat, 10) : 0;
            }
            // Begin is an event name
            if (isNaN(begin)) { begin = 0; }
            // Save a copy of current value to restore it later
            this.initValue = utils.mixin({}, current);
            var direction = this.getDirection(data.direction);
            var toTemp = to;
            // Swap from and to
            if (direction === 'reverse') {
              to = utils.mixin({}, from);
              from = utils.mixin({}, toTemp);
            }
            if (fill === 'backwards' || fill === 'both') {
              el.setAttribute(attribute, from);
            }
            this.tween = new TWEEN.Tween(from)
              .to(to, data.dur)
              .delay(begin)
              .easing(easing)
              .repeat(repeat)
              .onUpdate(function () {
                el.setAttribute(data.attribute, this);
              })
              .onComplete(this.onCompleted.bind(this));
            return tween;
          },
          writable: window.debug
        },

        getDirection: {
          value: function (direction) {
            if (direction === 'alternate') {
              this.lastDirection = this.lastDirection === 'normal' ? 'reverse' : 'normal';
              return this.lastDirection;
            }
            if (direction === 'alternate-reverse') {
              this.lastDirection = this.lastDirection === 'reverse' ? 'normal' : 'reverse';
              return this.lastDirection;
            }
            return direction;
          },
          writable: window.debug
        },

        onCompleted: {
          value: function () {
            var el = this.el;
            var data = this.data;
            this.running = false;
            if (data.fill === 'none') {
              el.setAttribute(data.attribute, this.initValue);
            }
            if (this.count === 0) {
              this.count = undefined;
              this.emit('animationend');
              return;
            }
            this.running = false;
            this.count -= 1;
            this.start();
          },
          writable: true
        },

        stop: {
          value: function () {
            var el = this.el;
            var data = this.data;
            var tween = this.tween;
            if (!tween) { return; }
            tween.stop();
            this.running = false;
            el.setAttribute(data.attribute, this.initValue);
          },
          writable: true
        },

        start: {
          value: function () {
            var tween;
            if (this.running) { return; }
            this.init();
            tween = this.tween;
            this.running = true;
            tween.start();
            this.emit('animationstart');
          },
          // For preemptive binding. See update method
          writable: true
        },

        applyMixin: {
          value: function () {
            var data = {};
            var mixinData = this.getMixinData();
            var elData = this.getElData(this);
            utils.mixin(data, defaults);
            utils.mixin(data, mixinData);
            utils.mixin(data, elData);
            this.data = data;
            this.update();
          },
          writable: window.debug
        },

        getMixinData: {
          value: function () {
            var mixinId = this.getAttribute('mixin');
            var mixinEl = document.querySelector('#' + mixinId);
            if (!mixinEl) { return {}; }
            return this.getElData(mixinEl);
          },
          writable: window.debug
        },

        getElData: {
          value: function (el) {
            var data = {};
            Object.keys(defaults).forEach(copyAttribute);
            function copyAttribute (key) {
              if (el.hasAttribute(key)) {
                data[key] = el.getAttribute(key);
              }
            }
            return data;
          },
          writable: window.debug
        }
      })
  }
);
<commit_msg>Tween internally uses the from object to accumulate the animation changes. We need to pass a copy of the from attribute to preserve the original values.<commit_after>var registerElement = require('../vr-register-element').registerElement;

var TWEEN = require('tween.js');
var VRNode = require('./vr-node');
var utils = require('../vr-utils');

var defaults = {
  attribute: 'rotation',
  begin: '0',
  dur: 1000,
  easing: 'ease',
  direction: 'normal',
  fill: 'none',
  from: { x: 0, y: 0, z: 0 },
  repeat: 0,
  to: undefined
};

var easingFunctions = {
  'ease': TWEEN.Easing.Cubic.InOut,
  'linear': TWEEN.Easing.Linear.None,
  'ease-in': TWEEN.Easing.Cubic.In,
  'ease-out': TWEEN.Easing.Cubic.Out,
  'ease-in-out': TWEEN.Easing.Cubic.InOut
};

module.exports = registerElement(
  'vr-animation', {
    prototype: Object.create(
      VRNode.prototype, {
        attachedCallback: {
          value: function () {
            this.el = this.parentNode;
            // preemptive binding to attach/dettach event listeners (see update method)
            this.bindMethods();
            this.applyMixin();
            this.load();
          },
          writable: window.debug
        },

        bindMethods: {
          value: function () {
            this.start = this.start.bind(this);
            this.stop = this.stop.bind(this);
            this.onStateAdded = this.onStateAdded.bind(this);
            this.onStateRemoved = this.onStateRemoved.bind(this);
          },
          writable: window.debug
        },

        attributeChangedCallback: {
          value: function () {
            this.stop();
            this.applyMixin();
          },
          writable: window.debug
        },

        update: {
          value: function () {
            var data = this.data;
            var begin = data.begin;
            // begin is an event name
            // Cancel previous event listeners
            this.removeEventListeners(this.evt);
            this.addEventListeners(begin);
            // Store new event name
            this.evt = begin;
            // If begin is a number we start the animation right away
            if (!isNaN(begin)) {
              this.stop();
              this.start();
              return;
            }
          }
        },

        addEventListeners: {
          value: function (evt) {
            var el = this.el;
            el.addEventListener(evt, this.start);
            el.addEventListener('stateadded', this.onStateAdded);
            el.addEventListener('stateremoved', this.onStateRemoved);
          },
          writable: window.debug
        },

        removeEventListeners: {
          value: function (evt) {
            var el = this.el;
            el.removeEventListener(evt, this.start);
            el.removeEventListener('stateadded', this.onStateAdded);
            el.removeEventListener('stateremoved', this.onStateRemoved);
          },
          writable: window.debug
        },

        onStateAdded: {
          value: function (evt) {
            if (evt.detail.state === this.data.begin) {
              this.start();
            }
          },
          writable: true
        },

        onStateRemoved: {
          value: function (evt) {
            if (evt.detail.state === this.data.begin) {
              this.stop();
            }
          },
          writable: true
        },

        init: {
          value: function () {
            // Stop previous tween
            var data = this.data;
            var repeat = data.repeat === 'indefinite' ? Infinity : 0;
            var el = this.el;
            var attribute = data.attribute;
            var current = el.getComputedAttribute(attribute);
            var from = data.from ? utils.parseCoordinate(data.from) : current;
            var tween = this.tween;
            var begin = parseInt(data.begin, 10);
            var to = utils.parseCoordinate(data.to);
            var easing = easingFunctions[data.easing];
            var fill = data.fill;
            var count = this.count;
            if (count === undefined) {
              this.count = repeat !== Infinity ? parseInt(data.repeat, 10) : 0;
            }
            // Begin is an event name
            if (isNaN(begin)) { begin = 0; }
            // Save a copy of current value to restore it later
            this.initValue = utils.mixin({}, current);
            var direction = this.getDirection(data.direction);
            var toTemp = to;
            // Swap from and to
            if (direction === 'reverse') {
              to = utils.mixin({}, from);
              from = utils.mixin({}, toTemp);
            }
            if (fill === 'backwards' || fill === 'both') {
              el.setAttribute(attribute, from);
            }
            this.tween = new TWEEN.Tween(utils.mixin({}, from))
              .to(to, data.dur)
              .delay(begin)
              .easing(easing)
              .repeat(repeat)
              .onUpdate(function () {
                el.setAttribute(data.attribute, this);
              })
              .onComplete(this.onCompleted.bind(this));
            return tween;
          },
          writable: window.debug
        },

        getDirection: {
          value: function (direction) {
            if (direction === 'alternate') {
              this.lastDirection = this.lastDirection === 'normal' ? 'reverse' : 'normal';
              return this.lastDirection;
            }
            if (direction === 'alternate-reverse') {
              this.lastDirection = this.lastDirection === 'reverse' ? 'normal' : 'reverse';
              return this.lastDirection;
            }
            return direction;
          },
          writable: window.debug
        },

        onCompleted: {
          value: function () {
            var el = this.el;
            var data = this.data;
            this.running = false;
            if (data.fill === 'none') {
              el.setAttribute(data.attribute, this.initValue);
            }
            if (this.count === 0) {
              this.count = undefined;
              this.emit('animationend');
              return;
            }
            this.running = false;
            this.count -= 1;
            this.start();
          },
          writable: true
        },

        stop: {
          value: function () {
            var el = this.el;
            var data = this.data;
            var tween = this.tween;
            if (!tween) { return; }
            tween.stop();
            this.running = false;
            el.setAttribute(data.attribute, this.initValue);
          },
          writable: true
        },

        start: {
          value: function () {
            var tween;
            if (this.running) { return; }
            this.init();
            tween = this.tween;
            this.running = true;
            tween.start();
            this.emit('animationstart');
          },
          // For preemptive binding. See update method
          writable: true
        },

        applyMixin: {
          value: function () {
            var data = {};
            var mixinData = this.getMixinData();
            var elData = this.getElData(this);
            utils.mixin(data, defaults);
            utils.mixin(data, mixinData);
            utils.mixin(data, elData);
            this.data = data;
            this.update();
          },
          writable: window.debug
        },

        getMixinData: {
          value: function () {
            var mixinId = this.getAttribute('mixin');
            var mixinEl = document.querySelector('#' + mixinId);
            if (!mixinEl) { return {}; }
            return this.getElData(mixinEl);
          },
          writable: window.debug
        },

        getElData: {
          value: function (el) {
            var data = {};
            Object.keys(defaults).forEach(copyAttribute);
            function copyAttribute (key) {
              if (el.hasAttribute(key)) {
                data[key] = el.getAttribute(key);
              }
            }
            return data;
          },
          writable: window.debug
        }
      })
  }
);
<|endoftext|>


<commit_before>importScripts('lib/underscore.js');

onmessage = function(message) {

  function parseCSV(rawCSV) {
    var patterns = new RegExp((
      // Delimiters.
      "(\\,|\\r?\\n|\\r|^)" +
      // Quoted fields.
      "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
      // Standard fields.
      "([^\"\\,\\r\\n]*))"
    ), "gi");

    var rows = [[]], matches = null;

    while (matches = patterns.exec(rawCSV)) {
      var delimiter = matches[1];

      if (delimiter.length && (delimiter !== ",")) rows.push([]);

      if (matches[2]) {
        var value = matches[2].replace(new RegExp("\"\"", "g"), "\"");
      } else {
        var value = matches[3];
      }
      rows[rows.length - 1].push(value);
    }

    if(_.isEqual(rows[rows.length -1], [""])) rows.pop();

    var docs = [];
    var headers = _.first(rows);
    _.each(_.rest(rows), function(row, rowIDX) {
      var doc = {};
      _.each(row, function(cell, idx) {
        doc[headers[idx]] = cell;
      })
      docs.push(doc);
    })

    return docs;
  }

  var docs = parseCSV(message.data.data);

  var req = new XMLHttpRequest();

  req.onprogress = req.upload.onprogress = function(e) {
    if(e.lengthComputable) postMessage({ percent: (e.loaded / e.total) * 100 });
  };

  req.onreadystatechange = function() { if (req.readyState == 4) postMessage({done: true, response: req.responseText}) };
  req.open('POST', message.data.url);
  req.setRequestHeader('Content-Type', 'application/json');
  req.send(JSON.stringify({docs: docs}));
};
<commit_msg>[costco-csv-worker][xs]: comment out importScripts('lib/underscore.js') since does not work in normal JS.<commit_after>// importScripts('lib/underscore.js');

onmessage = function(message) {

  function parseCSV(rawCSV) {
    var patterns = new RegExp((
      // Delimiters.
      "(\\,|\\r?\\n|\\r|^)" +
      // Quoted fields.
      "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
      // Standard fields.
      "([^\"\\,\\r\\n]*))"
    ), "gi");

    var rows = [[]], matches = null;

    while (matches = patterns.exec(rawCSV)) {
      var delimiter = matches[1];

      if (delimiter.length && (delimiter !== ",")) rows.push([]);

      if (matches[2]) {
        var value = matches[2].replace(new RegExp("\"\"", "g"), "\"");
      } else {
        var value = matches[3];
      }
      rows[rows.length - 1].push(value);
    }

    if(_.isEqual(rows[rows.length -1], [""])) rows.pop();

    var docs = [];
    var headers = _.first(rows);
    _.each(_.rest(rows), function(row, rowIDX) {
      var doc = {};
      _.each(row, function(cell, idx) {
        doc[headers[idx]] = cell;
      })
      docs.push(doc);
    })

    return docs;
  }

  var docs = parseCSV(message.data.data);

  var req = new XMLHttpRequest();

  req.onprogress = req.upload.onprogress = function(e) {
    if(e.lengthComputable) postMessage({ percent: (e.loaded / e.total) * 100 });
  };

  req.onreadystatechange = function() { if (req.readyState == 4) postMessage({done: true, response: req.responseText}) };
  req.open('POST', message.data.url);
  req.setRequestHeader('Content-Type', 'application/json');
  req.send(JSON.stringify({docs: docs}));
};
<|endoftext|>


<commit_before>'use strict';

var Radium = require('radium');
var toolbarHeight = '50px';

var closeWindowKeyframes = Radium.keyframes({
    '0%': {opacity: '1'},
    '100%': {opacity: '0'},
}, 'closeWindow');

var styles = {
    outer: {
        backgroundColor : 'rgba(0, 0, 0, 0.85)',
        position        : 'fixed',
        top             : 0,
        left            : 0,
        right           : 0,
        bottom          : 0,
        zIndex          : 1000,
        width           : '100%',
        height          : '100%',
    },
    outerAnimating: function(duration, isClosing) {
        return {
            transition         : 'opacity ' + String(duration) + 'ms',
            animationDuration  : String(duration) + 'ms',
            animationDirection : isClosing ? 'normal' : 'reverse',
            animationName      : closeWindowKeyframes,
        };
    },
    outerClosing: {
        opacity: 0,
    },
    inner: {
        position : 'absolute',
        top      : 0,
        left     : 0,
        right    : 0,
        bottom   : 0,
    },

    image: {
        position   : 'absolute',
        top        : 0,
        bottom     : 0,
        margin     : 'auto',
        maxWidth   : '100%',
        maxHeight  : '100%',
    },
    imagePrev: {
        left: '-100%',
        right: '100%',
    },
    imageNext: {
        left: '100%',
        right: '-100%',
    },
    imageCurrent: {
        left: 0,
        right: 0,
    },
    imageDiscourager: {
        backgroundRepeat   : 'no-repeat',
        backgroundPosition : 'center',
        backgroundSize     : 'contain',
    },
    imageAnimating: function(duration) {
        return {
            transition: [
                'left '  + String(duration) + 'ms',
                'right ' + String(duration) + 'ms',
            ].join(', '),
        };
    },

    navButtons: {
        border   : 'none',
        position : 'absolute',
        top      : 0,
        bottom   : 0,
        width    : '20px',
        height   : '34px',
        padding  : '40px 40px',
        margin   : 'auto',
        cursor   : 'pointer',
        opacity  : 0.7,

        ':hover': {
            opacity: 1,
        },

        ':active': {
            opacity: 0.7,
        },
    },
    navButtonPrev: {
        left       : 0,
        background : 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjM0Ij48cGF0aCBkPSJtIDE5LDMgLTIsLTIgLTE2LDE2IDE2LDE2IDEsLTEgLTE1LC0xNSAxNSwtMTUgeiIgZmlsbD0iI0ZGRiIvPjwvc3ZnPg==\') no-repeat center',
    },
    navButtonNext: {
        right      : 0,
        background : 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjM0Ij48cGF0aCBkPSJtIDEsMyAyLC0yIDE2LDE2IC0xNiwxNiAtMSwtMSAxNSwtMTUgLTE1LC0xNSB6IiBmaWxsPSIjRkZGIi8+PC9zdmc+\') no-repeat center',
    },

    downloadBlocker: {
        position        : 'absolute',
        top             : 0,
        left            : 0,
        right           : 0,
        bottom          : 0,
        backgroundImage : 'url(\'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\')',
        backgroundSize  : 'cover',
    },

    toolbar: {
        backgroundColor : 'rgba(0, 0, 0, 0.5)',
        position        : 'absolute',
        left            : 0,
        top             : 0,
        right           : 0,
        height          : toolbarHeight,
    },
    toolbarSide: {
        lineHeight : toolbarHeight,
        position   : 'absolute',
        top        : 0,
        bottom     : 0,
        margin     : 0,
        maxWidth   : '48%',
    },
    toolbarLeftSide: {
        paddingLeft  : '20px',
        paddingRight : 0,
        left         : 0,
    },
    toolbarRightSide: {
        paddingLeft  : 0,
        paddingRight : '20px',
        right        : 0,
    },
    toolbarItem: {
        display       : 'inline-block',
        lineHeight    : toolbarHeight,
        padding       : '0 6px',
        color         : '#FFFFFF',
        fontSize      : '120%',
        maxWidth      : '100%',
        overflow      : 'hidden',
        textOverflow  : 'ellipsis',
        whiteSpace    : 'nowrap',

    },
    toolbarItemChild: {
        verticalAlign: 'middle',
    },

    builtinButton: {
        width      : '25px',
        height     : '25px',
        cursor     : 'pointer',
        border     : 'none',

        ':hover': {
            opacity: 0.7,
        },

        ':active': {
            outline: 'none',
        },
    },

    closeButton: {
        background: 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIj48cGF0aCBkPSJtIDEsMyAxLjI1LC0xLjI1IDcuNSw3LjUgNy41LC03LjUgMS4yNSwxLjI1IC03LjUsNy41IDcuNSw3LjUgLTEuMjUsMS4yNSAtNy41LC03LjUgLTcuNSw3LjUgLTEuMjUsLTEuMjUgNy41LC03LjUgLTcuNSwtNy41IHoiIGZpbGw9IiNGRkYiLz48L3N2Zz4=\') no-repeat center',
    },

    zoomInButton: {
        background: 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCI+PGcgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0iTTEgMTlsNi02Ii8+PHBhdGggZD0iTTkgOGg2Ii8+PHBhdGggZD0iTTEyIDV2NiIvPjwvZz48Y2lyY2xlIGN4PSIxMiIgY3k9IjgiIHI9IjciIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIi8+PC9zdmc+\') no-repeat center',
    },

    zoomOutButton: {
        background: 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCI+PGcgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0iTTEgMTlsNi02Ii8+PHBhdGggZD0iTTkgOGg2Ii8+PC9nPjxjaXJjbGUgY3g9IjEyIiBjeT0iOCIgcj0iNyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48L3N2Zz4=\') no-repeat center',
    },
};

module.exports = styles;
<commit_msg>Make navigation buttons more visible when over bright pictures<commit_after>'use strict';

var Radium = require('radium');
var toolbarHeight = '50px';

var closeWindowKeyframes = Radium.keyframes({
    '0%': {opacity: '1'},
    '100%': {opacity: '0'},
}, 'closeWindow');

var styles = {
    outer: {
        backgroundColor : 'rgba(0, 0, 0, 0.85)',
        position        : 'fixed',
        top             : 0,
        left            : 0,
        right           : 0,
        bottom          : 0,
        zIndex          : 1000,
        width           : '100%',
        height          : '100%',
    },
    outerAnimating: function(duration, isClosing) {
        return {
            transition         : 'opacity ' + String(duration) + 'ms',
            animationDuration  : String(duration) + 'ms',
            animationDirection : isClosing ? 'normal' : 'reverse',
            animationName      : closeWindowKeyframes,
        };
    },
    outerClosing: {
        opacity: 0,
    },
    inner: {
        position : 'absolute',
        top      : 0,
        left     : 0,
        right    : 0,
        bottom   : 0,
    },

    image: {
        position   : 'absolute',
        top        : 0,
        bottom     : 0,
        margin     : 'auto',
        maxWidth   : '100%',
        maxHeight  : '100%',
    },
    imagePrev: {
        left: '-100%',
        right: '100%',
    },
    imageNext: {
        left: '100%',
        right: '-100%',
    },
    imageCurrent: {
        left: 0,
        right: 0,
    },
    imageDiscourager: {
        backgroundRepeat   : 'no-repeat',
        backgroundPosition : 'center',
        backgroundSize     : 'contain',
    },
    imageAnimating: function(duration) {
        return {
            transition: [
                'left '  + String(duration) + 'ms',
                'right ' + String(duration) + 'ms',
            ].join(', '),
        };
    },

    navButtons: {
        border   : 'none',
        position : 'absolute',
        top      : 0,
        bottom   : 0,
        width    : '20px',
        height   : '34px',
        padding  : '40px 30px',
        margin   : 'auto',
        cursor   : 'pointer',
        opacity  : 0.7,

        ':hover': {
            opacity: 1,
        },

        ':active': {
            opacity: 0.7,
        },
    },
    navButtonPrev: {
        left       : 0,
        background : 'rgba(0,0,0,0.2) url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjM0Ij48cGF0aCBkPSJtIDE5LDMgLTIsLTIgLTE2LDE2IDE2LDE2IDEsLTEgLTE1LC0xNSAxNSwtMTUgeiIgZmlsbD0iI0ZGRiIvPjwvc3ZnPg==\') no-repeat center',
    },
    navButtonNext: {
        right      : 0,
        background : 'rgba(0,0,0,0.2) url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjM0Ij48cGF0aCBkPSJtIDEsMyAyLC0yIDE2LDE2IC0xNiwxNiAtMSwtMSAxNSwtMTUgLTE1LC0xNSB6IiBmaWxsPSIjRkZGIi8+PC9zdmc+\') no-repeat center',
    },

    downloadBlocker: {
        position        : 'absolute',
        top             : 0,
        left            : 0,
        right           : 0,
        bottom          : 0,
        backgroundImage : 'url(\'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\')',
        backgroundSize  : 'cover',
    },

    toolbar: {
        backgroundColor : 'rgba(0, 0, 0, 0.5)',
        position        : 'absolute',
        left            : 0,
        top             : 0,
        right           : 0,
        height          : toolbarHeight,
    },
    toolbarSide: {
        lineHeight : toolbarHeight,
        position   : 'absolute',
        top        : 0,
        bottom     : 0,
        margin     : 0,
        maxWidth   : '48%',
    },
    toolbarLeftSide: {
        paddingLeft  : '20px',
        paddingRight : 0,
        left         : 0,
    },
    toolbarRightSide: {
        paddingLeft  : 0,
        paddingRight : '20px',
        right        : 0,
    },
    toolbarItem: {
        display       : 'inline-block',
        lineHeight    : toolbarHeight,
        padding       : '0 6px',
        color         : '#FFFFFF',
        fontSize      : '120%',
        maxWidth      : '100%',
        overflow      : 'hidden',
        textOverflow  : 'ellipsis',
        whiteSpace    : 'nowrap',

    },
    toolbarItemChild: {
        verticalAlign: 'middle',
    },

    builtinButton: {
        width      : '25px',
        height     : '25px',
        cursor     : 'pointer',
        border     : 'none',

        ':hover': {
            opacity: 0.7,
        },

        ':active': {
            outline: 'none',
        },
    },

    closeButton: {
        background: 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIj48cGF0aCBkPSJtIDEsMyAxLjI1LC0xLjI1IDcuNSw3LjUgNy41LC03LjUgMS4yNSwxLjI1IC03LjUsNy41IDcuNSw3LjUgLTEuMjUsMS4yNSAtNy41LC03LjUgLTcuNSw3LjUgLTEuMjUsLTEuMjUgNy41LC03LjUgLTcuNSwtNy41IHoiIGZpbGw9IiNGRkYiLz48L3N2Zz4=\') no-repeat center',
    },

    zoomInButton: {
        background: 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCI+PGcgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0iTTEgMTlsNi02Ii8+PHBhdGggZD0iTTkgOGg2Ii8+PHBhdGggZD0iTTEyIDV2NiIvPjwvZz48Y2lyY2xlIGN4PSIxMiIgY3k9IjgiIHI9IjciIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIi8+PC9zdmc+\') no-repeat center',
    },

    zoomOutButton: {
        background: 'url(\'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCI+PGcgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0iTTEgMTlsNi02Ii8+PHBhdGggZD0iTTkgOGg2Ii8+PC9nPjxjaXJjbGUgY3g9IjEyIiBjeT0iOCIgcj0iNyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48L3N2Zz4=\') no-repeat center',
    },
};

module.exports = styles;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import idgen from './idgen';

const Switch = ({
  id,
  className,
  checked,
  onChange,
  disabled,
  offLabel,
  onLabel
}) => {
  const computedId = id || idgen();

  return (

        {offLabel}
        <input
          id={computedId}
          className={className}
          disabled={disabled}
          onChange={onChange}
          type="checkbox"
          checked={checked}
        />

        {onLabel}

  );
};

Switch.propTypes = {
  /*
   * override id
   * @default idgen()
   */
  id: PropTypes.string,
  className: PropTypes.string,
  /*
   * label for off
   */
  offLabel: PropTypes.string.isRequired,
  /*
   * label for on
   */
  onLabel: PropTypes.string.isRequired,
  /*
   * onChange callback
   */
  onChange: PropTypes.func,
  /*
   * disabled input
   */
  disabled: PropTypes.bool,
  /*
   * initialise checkbox checked
   */
  checked: PropTypes.bool
};

export default Switch;
<commit_msg>fix: spread all props<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import idgen from './idgen';

const Switch = ({
  id,
  checked,
  onChange,
  disabled,
  offLabel,
  onLabel,
  ...props
}) => {
  return (

        {offLabel}
        <input
          id={id}
          disabled={disabled}
          onChange={onChange}
          type="checkbox"
          checked={checked}
          {...props}
        />

        {onLabel}

  );
};

Switch.propTypes = {
  /*
   * override id
   * @default idgen()
   */
  id: PropTypes.string.isRequired,
  className: PropTypes.string,
  /*
   * label for off
   */
  offLabel: PropTypes.string.isRequired,
  /*
   * label for on
   */
  onLabel: PropTypes.string.isRequired,
  /*
   * onChange callback
   */
  onChange: PropTypes.func,
  /*
   * disabled input
   */
  disabled: PropTypes.bool,
  /*
   * initialise checkbox checked
   */
  checked: PropTypes.bool
};

Switch.defaultProps = {
  id: idgen()
};

export default Switch;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { View, StyleSheet } from 'react-native';
import Tabs from 'react-native-tabs';
import DefaultRenderer from './DefaultRenderer';
import Actions from './Actions';
import TabbedView from './TabbedView';
import { assert } from './Util';

class TabBar extends Component {

  static propTypes = {
    navigationState: PropTypes.object,
    tabIcon: PropTypes.any,
  };

  constructor(props, context) {
    super(props, context);
    this.renderScene = this.renderScene.bind(this);
  }

  onSelect(el) {
    if (!Actions[el.props.name]) {
      throw new Error(
        `No action is defined for name=${el.props.name} ` +
        `actions: ${JSON.stringify(Object.keys(Actions))}`);
    }
    Actions[el.props.name]();
  }

  renderScene(navigationState, index) {
    return <DefaultRenderer
      key={navigationState.key}
      onNavigate={this.props.onNavigate}
      navigationState={navigationState}
    />
  }

  render() {
    const state = this.props.navigationState;

    let selected = state.children[state.index];
    while (selected.hasOwnProperty('children')) {
      selected = selected.children[selected.index];
    }

    const hideTabBar = state.hideTabBar || selected.hideTabBar;

    return (
      <View
        style={{ flex: 1 }}
      >
        <TabbedView
          navigationState={this.props.navigationState}
          style={{ flex: 1 }}
          renderScene={this.renderScene}
        />
        {!hideTabBar && state.children.filter(el => el.icon).length > 0 &&
          <Tabs
            style={[{ backgroundColor: 'white' }, state.tabBarStyle]}
            onSelect={this.onSelect} {...state}
            selected={state.children[state.index].sceneKey}
          >
            {state.children.filter(el => el.icon || this.props.tabIcon).map(el => {
              const Icon = el.icon || this.props.tabIcon;
              return <Icon {...this.props} {...el} />;
            })}
          </Tabs>
        }
      </View>
    );
  }

}

export default TabBar;
<commit_msg>add onNavigate prop<commit_after>import React, { Component, PropTypes } from 'react';
import { View, StyleSheet } from 'react-native';
import Tabs from 'react-native-tabs';
import DefaultRenderer from './DefaultRenderer';
import Actions from './Actions';
import TabbedView from './TabbedView';
import { assert } from './Util';

class TabBar extends Component {

  static propTypes = {
    navigationState: PropTypes.object,
    tabIcon: PropTypes.any,
    onNavigate: PropTypes.func,
  };

  constructor(props, context) {
    super(props, context);
    this.renderScene = this.renderScene.bind(this);
  }

  onSelect(el) {
    if (!Actions[el.props.name]) {
      throw new Error(
        `No action is defined for name=${el.props.name} ` +
        `actions: ${JSON.stringify(Object.keys(Actions))}`);
    }
    Actions[el.props.name]();
  }

  renderScene(navigationState, index) {
    return <DefaultRenderer
      key={navigationState.key}
      onNavigate={this.props.onNavigate}
      navigationState={navigationState}
    />
  }

  render() {
    const state = this.props.navigationState;

    let selected = state.children[state.index];
    while (selected.hasOwnProperty('children')) {
      selected = selected.children[selected.index];
    }

    const hideTabBar = state.hideTabBar || selected.hideTabBar;

    return (
      <View
        style={{ flex: 1 }}
      >
        <TabbedView
          navigationState={this.props.navigationState}
          style={{ flex: 1 }}
          renderScene={this.renderScene}
        />
        {!hideTabBar && state.children.filter(el => el.icon).length > 0 &&
          <Tabs
            style={[{ backgroundColor: 'white' }, state.tabBarStyle]}
            onSelect={this.onSelect} {...state}
            selected={state.children[state.index].sceneKey}
          >
            {state.children.filter(el => el.icon || this.props.tabIcon).map(el => {
              const Icon = el.icon || this.props.tabIcon;
              return <Icon {...this.props} {...el} />;
            })}
          </Tabs>
        }
      </View>
    );
  }

}

export default TabBar;
<|endoftext|>