<commit_before>/**
*
* s.Comm ---
* allows us to compartmentalize all interactions
* with the server to this class (s.Comm) --this class
* is the only place that holds the logic that allows
* the client to communicate with the server.
*
**/

s.Comm = new Class( {

    extend: s.EventEmitter,

    toString: "Comm",

    // makeTrigger is responsible for broadcasting all events

    // receieved from the server to the rest of the game.

    makeTrigger: function ( evt ) {
        var that = this;

        return function ( message ) {

            that.trigger.call( that, evt, message );

        };

    },

    destruct: function ( ) {

        // TODO: Send server some kind of destruct message?

    },

    construct: function ( options ) {

        //binding the game's context

        this.game = options.game;

        // Prepend http. Doing this so that you can customize the server before finalizing the string.

        options.server = 'http://' + options.server;

        this.player = options.player;

        this.delta = 0;

        this.ship = options.ship;

        this.pilot = options.pilot;

        this.room = options.room;

        var that = this;

        this.lastMessageTime = new Date( ).getTime( );

        // Create socket connection

        this.socket = io.connect( options.server );

        this.socket.on( 'join', this.makeTrigger( 'join' ) );

        this.socket.on( 'failed', function ( message ) {
            // try to reconnect
            that.connected( );
        } );

        this.socket.on( 'player list', this.makeTrigger( 'player list' ) );

        this.socket.on( 'leave', this.makeTrigger( 'leave' ) );

        this.socket.on( 'move', this.makeTrigger( 'move' ) );

        this.socket.on( 'killed', this.makeTrigger( 'killed' ));

        this.socket.on( 'fire', this.makeTrigger( 'fire' ));

        this.socket.on( 'hit', this.makeTrigger( 'hit' ));

        this.socket.on( 'sync', this.makeTrigger( 'sync'));

        this.socket.on( 'bot retrieval', this.makeTrigger( 'bot retrieval' ));

        this.socket.on( 'bot positions', this.makeTrigger( 'bot positions' ));

        this.game.hook( this.position );

        this.clockTick = this.clockTick.bind(this);

        this.timer = setInterval(this.clockTick,1000);

        this.time = 0;

    },

    connected: function ( ) {

        var time = new Date( ).getTime( );

        var shipPosition = this.game.player.getPositionPacket( );
        var packet = {
            room: this.room,

            evt: 'joined',

            name: this.pilot.name,

            time: time,

            pos: shipPosition.pos,

            rot: shipPosition.rot,

            aVeloc: shipPosition.aVeloc,

            lVeloc: shipPosition.lVeloc,

        };

        // Broadcast position

        this.socket.emit('join', packet );

    },

    position: function ( ) {
      if(this.lastPosition === undefined) {
        this.lastPosition = s.game.player.getPositionPacket( );
        this.lastTime = new Date().getTime();
      }
      var time = new Date( ).getTime( );
      var shipPosition = s.game.player.getPositionPacket( );
          shipPosition.lAccel = [];
          shipPosition.aAccel = [];
      var delta = function() {
        var results = {};
        var diff;
        var t_diff;
        for(var i = 0; i < 3; i++) {
          diff = shipPosition.lVeloc[i] - this.lastPosition.lVeloc[i];
          t_diff = time - this.lastTime;

          if(t_diff === 0 || isNaN(t_diff) ) {
            return "Invalid";
          } else {
            shipPosition.lAccel.push(diff/t_diff);
          }

          diff = shipPosition.aVeloc[i] - this.lastPosition.aVeloc[i];
          t_diff = time - this.lastTime;
          if(t_diff === 0 || isNaN(t_diff) ) {
            return "Invalid";
          } else {
            shipPosition.aAccel.push(diff/t_diff);
          }
        }
        return results;
      }();
      if(Math.abs(shipPosition.aAccel[0]) > 0.00015 ||
         Math.abs(shipPosition.aAccel[1]) > 0.00015 ||
         Math.abs(shipPosition.aAccel[2]) > 0.00015 ||
         Math.abs(shipPosition.lAccel[0]) > 0.00005 ||
         Math.abs(shipPosition.lAccel[1]) > 0.00005 ||
         Math.abs(shipPosition.lAccel[2]) > 0.00005 ) {
        var packet = {
          time: time,
          pos: shipPosition.pos,
          rot: shipPosition.rot,
          aVeloc: shipPosition.aVeloc,
          lVeloc: shipPosition.lVeloc,
          aAccel: shipPosition.aAccel,
          lAccel: shipPosition.lAccel
        };

        s.game.comm.socket.emit( 'combat','move', packet );
        s.game.comm.lastMessageTime = time;
        this.lastPosition = shipPosition;
        this.lastTime = time;
      }
    },

    fire: function( pos, rot, velocity ) {

        this.time = 0;

        this.socket.emit( 'combat','fire', {

            position: pos,

            rotation: rot,

            initialVelocity: velocity

        });
    },

    died: function( you, killer ) {

        this.socket.emit( 'player','killed',{

            you: you,

            killer: killer

             });

    },

    hit: function( otherPlayerName, yourName ) {

        this.time = 0;

        this.socket.emit( 'combat','hit', {

            otherPlayerName: otherPlayerName,

            yourName: yourName

        });
    },

    clockTick: function( ){
        this.time += 1;

        // if ( this.time >= 60 ){
        //     window.location.href = "http://satellite-game.com";
        // }
    },

    sendKey: function(direction, key){
        var time = new Date().getTime();
        // Never send faster than server can handle
        if ( time - s.game.comm.lastMessageTime >= 15 ) {
            var shipPosition = s.game.player.getPositionPacket();
            // TODO: Figure out if ship or turret actually moved
            // If ship moved, send packet
            if ( this.lastPosition !== shipPosition.pos ) {
                // Build packet
                this.time = 0;

                var packet = {
                    time: time,
                    room: this.room,
                    name: this.pilot.name,
                    pos: shipPosition.pos,
                    rot: shipPosition.rot,
                    aVeloc: shipPosition.aVeloc,
                    lVeloc: shipPosition.lVeloc
                };
                // Broadcast position
                this.socket.emit( 'keypress', direction, $.extend(packet, { direction: direction, key: key }) );
                s.game.comm.lastMessageTime = time;
                this.lastPosition = shipPosition.pos;
            }
        }
    },

    botInfo: function(message) {
        this.socket.emit('botInfo', message);
    },

    botHit: function( yourName, botName ) {

        this.time = 0;

        this.socket.emit( 'botHit', {

            yourName: yourName,

            botName: botName

        });
    },

    botUpdate: function(enemies) {
        this.socket.emit( 'botUpdate', enemies);
    }
} );
<commit_msg>eased up the threshold a little<commit_after>/**
*
* s.Comm ---
* allows us to compartmentalize all interactions
* with the server to this class (s.Comm) --this class
* is the only place that holds the logic that allows
* the client to communicate with the server.
*
**/

s.Comm = new Class( {

    extend: s.EventEmitter,

    toString: "Comm",

    // makeTrigger is responsible for broadcasting all events

    // receieved from the server to the rest of the game.

    makeTrigger: function ( evt ) {
        var that = this;

        return function ( message ) {

            that.trigger.call( that, evt, message );

        };

    },

    destruct: function ( ) {

        // TODO: Send server some kind of destruct message?

    },

    construct: function ( options ) {

        //binding the game's context

        this.game = options.game;

        // Prepend http. Doing this so that you can customize the server before finalizing the string.

        options.server = 'http://' + options.server;

        this.player = options.player;

        this.delta = 0;

        this.ship = options.ship;

        this.pilot = options.pilot;

        this.room = options.room;

        var that = this;

        this.lastMessageTime = new Date( ).getTime( );

        // Create socket connection

        this.socket = io.connect( options.server );

        this.socket.on( 'join', this.makeTrigger( 'join' ) );

        this.socket.on( 'failed', function ( message ) {
            // try to reconnect
            that.connected( );
        } );

        this.socket.on( 'player list', this.makeTrigger( 'player list' ) );

        this.socket.on( 'leave', this.makeTrigger( 'leave' ) );

        this.socket.on( 'move', this.makeTrigger( 'move' ) );

        this.socket.on( 'killed', this.makeTrigger( 'killed' ));

        this.socket.on( 'fire', this.makeTrigger( 'fire' ));

        this.socket.on( 'hit', this.makeTrigger( 'hit' ));

        this.socket.on( 'sync', this.makeTrigger( 'sync'));

        this.socket.on( 'bot retrieval', this.makeTrigger( 'bot retrieval' ));

        this.socket.on( 'bot positions', this.makeTrigger( 'bot positions' ));

        this.game.hook( this.position );

        this.clockTick = this.clockTick.bind(this);

        this.timer = setInterval(this.clockTick,1000);

        this.time = 0;

    },

    connected: function ( ) {

        var time = new Date( ).getTime( );

        var shipPosition = this.game.player.getPositionPacket( );
        var packet = {
            room: this.room,

            evt: 'joined',

            name: this.pilot.name,

            time: time,

            pos: shipPosition.pos,

            rot: shipPosition.rot,

            aVeloc: shipPosition.aVeloc,

            lVeloc: shipPosition.lVeloc,

        };

        // Broadcast position

        this.socket.emit('join', packet );

    },

    position: function ( ) {
      if(this.lastPosition === undefined) {
        this.lastPosition = s.game.player.getPositionPacket( );
        this.lastTime = new Date().getTime();
      }
      var time = new Date( ).getTime( );
      var shipPosition = s.game.player.getPositionPacket( );
          shipPosition.lAccel = [];
          shipPosition.aAccel = [];
      var delta = function() {
        var results = {};
        var diff;
        var t_diff;
        for(var i = 0; i < 3; i++) {
          diff = shipPosition.lVeloc[i] - this.lastPosition.lVeloc[i];
          t_diff = time - this.lastTime;

          if(t_diff === 0 || isNaN(t_diff) ) {
            return "Invalid";
          } else {
            shipPosition.lAccel.push(diff/t_diff);
          }

          diff = shipPosition.aVeloc[i] - this.lastPosition.aVeloc[i];
          t_diff = time - this.lastTime;
          if(t_diff === 0 || isNaN(t_diff) ) {
            return "Invalid";
          } else {
            shipPosition.aAccel.push(diff/t_diff);
          }
        }
        return results;
      }();
      if(Math.abs(shipPosition.aAccel[0]) > 0.00005 ||
         Math.abs(shipPosition.aAccel[1]) > 0.00005 ||
         Math.abs(shipPosition.aAccel[2]) > 0.00005 ||
         Math.abs(shipPosition.lAccel[0]) > 0.00005 ||
         Math.abs(shipPosition.lAccel[1]) > 0.00005 ||
         Math.abs(shipPosition.lAccel[2]) > 0.00005 ) {
        var packet = {
          time: time,
          pos: shipPosition.pos,
          rot: shipPosition.rot,
          aVeloc: shipPosition.aVeloc,
          lVeloc: shipPosition.lVeloc,
          aAccel: shipPosition.aAccel,
          lAccel: shipPosition.lAccel
        };

        s.game.comm.socket.emit( 'combat','move', packet );
        s.game.comm.lastMessageTime = time;
        this.lastPosition = shipPosition;
        this.lastTime = time;
      }
    },

    fire: function( pos, rot, velocity ) {

        this.time = 0;

        this.socket.emit( 'combat','fire', {

            position: pos,

            rotation: rot,

            initialVelocity: velocity

        });
    },

    died: function( you, killer ) {

        this.socket.emit( 'player','killed',{

            you: you,

            killer: killer

             });

    },

    hit: function( otherPlayerName, yourName ) {

        this.time = 0;

        this.socket.emit( 'combat','hit', {

            otherPlayerName: otherPlayerName,

            yourName: yourName

        });
    },

    clockTick: function( ){
        this.time += 1;

        // if ( this.time >= 60 ){
        //     window.location.href = "http://satellite-game.com";
        // }
    },

    sendKey: function(direction, key){
        var time = new Date().getTime();
        // Never send faster than server can handle
        if ( time - s.game.comm.lastMessageTime >= 15 ) {
            var shipPosition = s.game.player.getPositionPacket();
            // TODO: Figure out if ship or turret actually moved
            // If ship moved, send packet
            if ( this.lastPosition !== shipPosition.pos ) {
                // Build packet
                this.time = 0;

                var packet = {
                    time: time,
                    room: this.room,
                    name: this.pilot.name,
                    pos: shipPosition.pos,
                    rot: shipPosition.rot,
                    aVeloc: shipPosition.aVeloc,
                    lVeloc: shipPosition.lVeloc
                };
                // Broadcast position
                this.socket.emit( 'keypress', direction, $.extend(packet, { direction: direction, key: key }) );
                s.game.comm.lastMessageTime = time;
                this.lastPosition = shipPosition.pos;
            }
        }
    },

    botInfo: function(message) {
        this.socket.emit('botInfo', message);
    },

    botHit: function( yourName, botName ) {

        this.time = 0;

        this.socket.emit( 'botHit', {

            yourName: yourName,

            botName: botName

        });
    },

    botUpdate: function(enemies) {
        this.socket.emit( 'botUpdate', enemies);
    }
} );
<|endoftext|>


<commit_before>'use strict';

/* scripts task
   ---------------
   Bundle javascripty things!
   This task is set up to generate multiple separate bundles,
   from different sources, and to use watch when run from the default task.
*/

var browserSync = require( 'browser-sync' );
var gulp = require( 'gulp' );
var gulpModernizr = require( 'gulp-modernizr' );
var gulpRename = require( 'gulp-rename' );
var gulpUglify = require( 'gulp-uglify' );
var handleErrors = require( '../utils/handleErrors' );
var paths = require( '../../config/environment' ).paths;
var webpackConfig = require( '../../config/webpack-config.js' );
var webpackStream = require( 'webpack-stream' );

/**
 * Generate modernizr polyfill bundle.
 * @returns {PassThrough} A source stream.
 */
function scriptsPolyfill() {
  return gulp.src( paths.unprocessed + '/js/routes/common.js' )
    .pipe( gulpModernizr( {
      tests:   [ 'csspointerevents', 'classlist', 'es5' ],
      options: [ 'setClasses',
                 'html5printshiv',
                 'fnBind' ]
    } ) )
    .pipe( gulpUglify() )
    .pipe( gulpRename( 'modernizr.min.js' ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

/**
 * Bundle scripts in unprocessed/js/routes/
 * and factor out common modules into common.js.
 * @returns {PassThrough} A source stream.
 */
function scriptsModern() {
  return gulp.src( paths.unprocessed + '/js/routes/common.js' )
    .pipe( webpackStream( webpackConfig.modernConf ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/routes/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

/**
 * Bundle IE9-specific script.
 * @returns {PassThrough} A source stream.
 */
function scriptsIE() {
  return gulp.src( paths.unprocessed + '/js/ie/common.ie.js' )
    .pipe( webpackStream( webpackConfig.ieConf ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/ie/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

/**
 * Bundle atomic component scripts.
 * Provides a means to bundle JS for specific atomic components,
 * which then can be carried over to other projects.
 * @returns {PassThrough} A source stream.
 */
function scriptsOnDemand() {
  return gulp.src( paths.unprocessed + '/js/routes/on-demand/*.js' )
    .pipe( webpackStream( webpackConfig.onDemandConf ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/atomic/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

/**
 * Bundle Es5 shim scripts.
 * @returns {PassThrough} A source stream.
 */
function scriptsEs5Shim() {
  return gulp.src( paths.unprocessed + '/js/shims/es5-shim.js' )
    .pipe( webpackStream( {
      entry: paths.unprocessed + '/js/shims/es5-shim.js',
      output: {
        filename: 'es5-shim.js'
      }
    } ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

gulp.task( 'scripts:polyfill', scriptsPolyfill );
gulp.task( 'scripts:modern', scriptsModern );
gulp.task( 'scripts:ie', scriptsIE );
gulp.task( 'scripts:ondemand', scriptsOnDemand );
gulp.task( 'scripts:es5-shim', scriptsEs5Shim );

gulp.task( 'scripts', [
  'scripts:polyfill',
  'scripts:modern',
  'scripts:ie',
  'scripts:es5-shim'
] );
<commit_msg>Uglify ES5 shim<commit_after>'use strict';

/* scripts task
   ---------------
   Bundle javascripty things!
   This task is set up to generate multiple separate bundles,
   from different sources, and to use watch when run from the default task.
*/

var browserSync = require( 'browser-sync' );
var gulp = require( 'gulp' );
var gulpModernizr = require( 'gulp-modernizr' );
var gulpRename = require( 'gulp-rename' );
var gulpUglify = require( 'gulp-uglify' );
var handleErrors = require( '../utils/handleErrors' );
var paths = require( '../../config/environment' ).paths;
var webpackConfig = require( '../../config/webpack-config.js' );
var webpackStream = require( 'webpack-stream' );

/**
 * Generate modernizr polyfill bundle.
 * @returns {PassThrough} A source stream.
 */
function scriptsPolyfill() {
  return gulp.src( paths.unprocessed + '/js/routes/common.js' )
    .pipe( gulpModernizr( {
      tests:   [ 'csspointerevents', 'classlist', 'es5' ],
      options: [ 'setClasses',
                 'html5printshiv',
                 'fnBind' ]
    } ) )
    .pipe( gulpUglify() )
    .pipe( gulpRename( 'modernizr.min.js' ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

/**
 * Bundle scripts in unprocessed/js/routes/
 * and factor out common modules into common.js.
 * @returns {PassThrough} A source stream.
 */
function scriptsModern() {
  return gulp.src( paths.unprocessed + '/js/routes/common.js' )
    .pipe( webpackStream( webpackConfig.modernConf ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/routes/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

/**
 * Bundle IE9-specific script.
 * @returns {PassThrough} A source stream.
 */
function scriptsIE() {
  return gulp.src( paths.unprocessed + '/js/ie/common.ie.js' )
    .pipe( webpackStream( webpackConfig.ieConf ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/ie/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

/**
 * Bundle atomic component scripts.
 * Provides a means to bundle JS for specific atomic components,
 * which then can be carried over to other projects.
 * @returns {PassThrough} A source stream.
 */
function scriptsOnDemand() {
  return gulp.src( paths.unprocessed + '/js/routes/on-demand/*.js' )
    .pipe( webpackStream( webpackConfig.onDemandConf ) )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/atomic/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

/**
 * Bundle Es5 shim scripts.
 * @returns {PassThrough} A source stream.
 */
function scriptsEs5Shim() {
  return gulp.src( paths.unprocessed + '/js/shims/es5-shim.js' )
    .pipe( webpackStream( {
      entry: paths.unprocessed + '/js/shims/es5-shim.js',
      output: {
        filename: 'es5-shim.js'
      }
    } ) )
    .pipe( gulpUglify() )
    .on( 'error', handleErrors )
    .pipe( gulp.dest( paths.processed + '/js/' ) )
    .pipe( browserSync.reload( {
      stream: true
    } ) );
}

gulp.task( 'scripts:polyfill', scriptsPolyfill );
gulp.task( 'scripts:modern', scriptsModern );
gulp.task( 'scripts:ie', scriptsIE );
gulp.task( 'scripts:ondemand', scriptsOnDemand );
gulp.task( 'scripts:es5-shim', scriptsEs5Shim );

gulp.task( 'scripts', [
  'scripts:polyfill',
  'scripts:modern',
  'scripts:ie',
  'scripts:es5-shim'
] );
<|endoftext|>


<commit_before>'use strict';

var merge = require('merge-stream');
var symlink = require('gulp-sym')

module.exports = function (gulp, plugins) {
    return function () {
        var config = {
            src: {
                html: 'src/**/*.html',
                py: 'src/**/*.py',
                css: 'src/css/**/*.css',
                ico: 'src/assets/ico/*.ico',
            },
            target: {
                html: 'dist',
                py: 'dist',
                css: 'dist/assets/css',
                ico: 'dist/assets/ico',
            }
        }

        var html = gulp.src(config.src.html)
            .pipe(gulp.dest(config.target.html));

        var py = gulp.src(config.src.py)
            .pipe(gulp.dest(config.target.py));

        var css = gulp.src(config.src.css)
            .pipe(gulp.dest(config.target.css));

        var ico = gulp.src(config.src.ico)
            .pipe(gulp.dest(config.target.ico));

        var systemJs = gulp.src('./src/assets/systemjs.config.js')
            .pipe(gulp.dest('dist/assets'));

        return merge(html, py, css, ico, systemJs);
    }
};
<commit_msg>Update copySrc.js<commit_after>'use strict';

var merge = require('merge-stream');
var symlink = require('gulp-sym')

module.exports = function (gulp, plugins) {
    return function () {
        var config = {
            src: {
                html: 'src/**/*.html',
                py: 'src/**/*.py',
                css: 'src/assets/css/**/*.css',
                ico: 'src/assets/ico/*.ico',
            },
            target: {
                html: 'dist',
                py: 'dist',
                css: 'dist/assets/css',
                ico: 'dist/assets/ico',
            }
        }

        var html = gulp.src(config.src.html)
            .pipe(gulp.dest(config.target.html));

        var py = gulp.src(config.src.py)
            .pipe(gulp.dest(config.target.py));

        var css = gulp.src(config.src.css)
            .pipe(gulp.dest(config.target.css));

        var ico = gulp.src(config.src.ico)
            .pipe(gulp.dest(config.target.ico));

        var systemJs = gulp.src('./src/assets/systemjs.config.js')
            .pipe(gulp.dest('dist/assets'));

        return merge(html, py, css, ico, systemJs);
    }
};
<|endoftext|>


<commit_before>function Inventory(world, camera, conn, controls) {
    var self = this;
    var BAG_SIZE = 25;
    var slots = [];

    var leftIsPrimary = true;
    var rightIsPrimary = true;

    function getEquippedSlot(isLeft, isPrimary) {
        index = BAG_SIZE;
        if (!isLeft) index += 2;
        if (!isPrimary) index += 1;
        return index;
    }

    function leftItem() {
        return slots[getEquippedSlot(true, leftIsPrimary)];
    }

    function rightItem() {
        return slots[getEquippedSlot(false, rightIsPrimary)];
    }

    var bagIsShowing = false;

    bagHtmlInit();
    updateHtmlEquipChanged(true);
    updateHtmlEquipChanged(false);

    conn.on('inventory-state', function (payload) {
        // Decode from the string
        var items = new Uint8Array(payload.Items.length);
        for (var i = 0; i < items.length; i++) {
            items[i] = payload.Items.charCodeAt(i) - 32;
        }

        // Create the item array, track if it changed
        if (!anyChanged(items)) return;
        var oldLeft = slots.length > 0 ? leftItem() : Item.NIL();
        var oldRight = slots.length > 0 ? rightItem() : Item.NIL();
        if (slots.length > items.length) slots = [];
        for (var i = 0; i < items.length; i++) {
            slots[i] = new Item(items[i]);
        }
        updateEquipped(oldLeft, oldRight);
        updateHtmlItemIcons();
    });

    function anyChanged(items) {
        if (slots.length !== items.length) return true;
        for (var i = 0; i < items.length; i++) {
            if (slots[i].type !== items[i]) return true;
        }
        return false;
    }

    var aspectRatio = 1.0;

    self.resize = function () {
        aspectRatio = window.innerWidth / window.innerHeight;
    };

    function bagHtmlInit() {
        var html = "";
        var classList;
        for (var y = 0; y < 5; y++) {
            for (var x = 0; x < 5; x++) {
                classList = "slot";
                if (x !== 0) classList += " has-left-sibling";
                if (y !== 0) classList += " has-top-sibling";
                html += '
'
                    + ''
                    + '
';
            }
        }
        updateBagVisibility();
        $("#bag").html(html);

        $("#leftPrimary").attr("index", BAG_SIZE);
        $("#leftReserve").attr("index", BAG_SIZE + 1);
        $("#rightPrimary").attr("index", BAG_SIZE + 2);
        $("#rightReserve").attr("index", BAG_SIZE + 3);

        $(".slot").each(function(i, obj) {
            var index = $(this).attr("index");
            $(this).children("img").draggable({
                helper: "clone",
                appendTo: "body",
                containment: "body",
                scroll: false,
                start: function (event, ui) {
                    $(this).attr("index", index);
                    ui.helper.css("z-index", 200);
                    $(this).css("visibility", "hidden");
                },
                revert: "invalid",
            });
        });
        $(".slot").droppable({
            drop: function(event, ui) {
                var from = ui.draggable.attr("index");
                var to = $(this).attr("index");
                conn.queue('inventory-move', {
                    From: from,
                    To: to,
                });
                updateItemMoved(ui.draggable.children("img"), $(this).children("img"));
                if (from === to) {
                    ui.draggable.css("visibility", "visible");
                } else {
                    ui.draggable.load(function () {
                        ui.draggable.css("visibility", "visible");
                    });
                }
            },
        });
    }

    function updateItemMoved(from, to) {
          var fromSrc = from.attr("src");
          var toSrc = to.attr("src");
          from.attr("src", toSrc);
          to.attr("src", fromSrc);
    }

    function updateHtmlEquipChanged(isLeft) {
        var side = isLeft ? "left" : "right";
        var primaryId = "#" + side + "Primary";
        var reserveId = "#" + side + "Reserve";
        if ((isLeft && leftIsPrimary) || (!isLeft && rightIsPrimary)) {
            $(primaryId).addClass("selected");
            $(reserveId).removeClass("selected");
        } else {
            $(primaryId).removeClass("selected");
            $(reserveId).addClass("selected");
        }
    }

    function updateHtmlItemIcons() {
        for (var y = 0; y < 5; y++) {
            for (var x = 0; x < 5; x++) {
                var index = y*5 + x;
                $("#bag" + index).children("img").attr("src", slots[index].icon());
            }
        }
        $("#leftPrimary").children("img").attr("src", slots[BAG_SIZE].icon());
        $("#leftReserve").children("img").attr("src", slots[BAG_SIZE + 1].icon());
        $("#rightPrimary").children("img").attr("src", slots[BAG_SIZE + 2].icon());
        $("#rightReserve").children("img").attr("src", slots[BAG_SIZE + 3].icon());
    }

    function updateEquipped(oldLeft, oldRight) {
        if (slots.length === 0) return;

        // Special case when switching left and right hands
        var skipModels = oldLeft != null
                      && oldRight != null
                      && oldLeft.model === rightItem().model
                      && oldRight.model === leftItem().model;

        if (!skipModels && oldLeft !== null) {
            swapModels(oldLeft, leftItem());
        }
        if (!skipModels && oldRight !== null) {
            swapModels(oldRight, rightItem());
        }

        conn.queue('inventory-state', {
            ItemLeft: getEquippedSlot(true, leftIsPrimary),
            ItemRight: getEquippedSlot(false, rightIsPrimary),
        });
    }

    function updateBagVisibility() {
        var $elm = $("#bag");
        if (bagIsShowing) {
            $elm.show();
            controls.unlock();
        } else {
            $elm.hide();
            controls.lock();
        }
    }

    function swapModels(oldItem, newItem) {
        if (oldItem.model !== null) {
            world.removeFromScene(oldItem.model);
        }
        var model = newItem.model;
        if (model !== null) {
            model.scale.set(1/16, 1/16, 1/16);
            world.addToScene(model);
        }
        return oldItem.type === newItem.type;
    }

    function pointItem(item, c) {
        var p = item.position;
        var target = new THREE.Vector3();
        target.x = p.x + sin(c.lat) * cos(c.lon);
        target.y = p.y + cos(c.lat);
        target.z = p.z + sin(c.lat) * sin(c.lon);
        item.lookAt(target);
    }

    function positionItem(item, playerPos, c) {
        var pp = playerPos;
        var ip = item.position;

        // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
        var theta = c.lat - 0.5;
        var phi = c.lon;
        var r = 0.15;
        var offset = sphericalToCartesian(r, theta, phi);
        ip.copy(pp).add(offset);
    }

    function sphericalToCartesian(r, theta, phi) {
        return new THREE.Vector3(
            r*sin(theta)*cos(phi),
            r*cos(theta),
            r*sin(theta)*sin(phi)
        );
    }

    function postitionPerspective(item, leftward) {
        var p = item.position;
        var r = new THREE.Matrix4();
        r.setRotationFromEuler(item.rotation, item.eulerOrder);

        var amount = leftward * aspectRatio * 0.05;

        // Move left / right
        var mov = new THREE.Vector3(amount, 0, 0);
        mov.applyMatrix3(r);

        p.add(mov);
    }

    var leftOffset = { x: Math.random(), z: Math.random() };
    var rightOffset = { x: Math.random(), z: Math.random() };
    function addJitter(item, values) {
        values.x += Math.random() / 30;
        values.z += Math.random() / 30;
        item.position.x += Math.sin(values.x) / 400;
        item.position.z += Math.sin(values.z) / 400;
    }

    var swapLeftWasDown = false;
    var swapRightWasDown = false;
    var toggleBagWasDown = false;
    self.update = function (playerPosition, controlState) {
        if (slots.length === 0) return;
        var p = playerPosition;
        var c = controlState;

        var leftWasDown = updateSide(true);
        var rightWasDown = updateSide(false);

        var toggleBagDown = c["toggleBag"];
        if (!toggleBagWasDown && toggleBagDown) {
            bagIsShowing = !bagIsShowing;
            updateBagVisibility();
        }
        toggleBagWasDown = toggleBagDown;

        swapLeftWasDown = leftWasDown;
        swapRightWasDown = rightWasDown;

        function activateItem(item) {
            var action = item.action();
            if (action) {
                action(world, camera);
            } else {
                console.log("Attempted to use an empty item slot.");
            }
        }

        function updateSide(isLeft) {
            var pos = isLeft ? 1 : -1;
            var offset = isLeft ? leftOffset : rightOffset;
            var swapWasDown = isLeft ? swapLeftWasDown : swapRightWasDown;
            var side = isLeft ? "Left" : "Right";
            var swapTrigger = "swap" + side;
            var activateTrigger = "activate" + side;
            var item = isLeft ? leftItem() : rightItem();
            var itemModel = item.model;

            if (itemModel !== null) {
                pointItem(itemModel, c);
                positionItem(itemModel, p, c);
                postitionPerspective(itemModel, pos);
                addJitter(itemModel, offset);
            }

            var swapDown = c[swapTrigger];
            if (!swapWasDown && swapDown) {
                if (isLeft) leftIsPrimary = !leftIsPrimary;
                else rightIsPrimary = !rightIsPrimary;
                updateEquipped((isLeft ? item : null),
                               (isLeft ? null : item));
                updateHtmlEquipChanged(isLeft);
            }

            if (c[activateTrigger]) {
                activateItem(item);
            }

            return swapDown;
        };
    };
}
<commit_msg>Fix in logic assumptions<commit_after>function Inventory(world, camera, conn, controls) {
    var self = this;
    var BAG_SIZE = 25;
    var slots = [];

    var leftIsPrimary = true;
    var rightIsPrimary = true;

    function getEquippedSlot(isLeft, isPrimary) {
        index = BAG_SIZE;
        if (!isLeft) index += 2;
        if (!isPrimary) index += 1;
        return index;
    }

    function leftItem() {
        return slots[getEquippedSlot(true, leftIsPrimary)];
    }

    function rightItem() {
        return slots[getEquippedSlot(false, rightIsPrimary)];
    }

    var bagIsShowing = false;

    bagHtmlInit();
    updateHtmlEquipChanged(true);
    updateHtmlEquipChanged(false);

    conn.on('inventory-state', function (payload) {
        // Decode from the string
        var items = new Uint8Array(payload.Items.length);
        for (var i = 0; i < items.length; i++) {
            items[i] = payload.Items.charCodeAt(i) - 32;
        }

        // Create the item array, track if it changed
        if (!anyChanged(items)) return;
        var oldLeft = slots.length > 0 ? leftItem() : Item.NIL();
        var oldRight = slots.length > 0 ? rightItem() : Item.NIL();
        if (slots.length > items.length) slots = [];
        for (var i = 0; i < items.length; i++) {
            slots[i] = new Item(items[i]);
        }
        updateEquipped(oldLeft, oldRight);
        updateHtmlItemIcons();
    });

    function anyChanged(items) {
        if (slots.length !== items.length) return true;
        for (var i = 0; i < items.length; i++) {
            if (slots[i].type !== items[i]) return true;
        }
        return false;
    }

    var aspectRatio = 1.0;

    self.resize = function () {
        aspectRatio = window.innerWidth / window.innerHeight;
    };

    function bagHtmlInit() {
        var html = "";
        var classList;
        for (var y = 0; y < 5; y++) {
            for (var x = 0; x < 5; x++) {
                classList = "slot";
                if (x !== 0) classList += " has-left-sibling";
                if (y !== 0) classList += " has-top-sibling";
                html += '
'
                    + ''
                    + '
';
            }
        }
        updateBagVisibility();
        $("#bag").html(html);

        $("#leftPrimary").attr("index", BAG_SIZE);
        $("#leftReserve").attr("index", BAG_SIZE + 1);
        $("#rightPrimary").attr("index", BAG_SIZE + 2);
        $("#rightReserve").attr("index", BAG_SIZE + 3);

        $(".slot").each(function(i, obj) {
            var index = $(this).attr("index");
            $(this).children("img").draggable({
                helper: "clone",
                appendTo: "body",
                containment: "body",
                scroll: false,
                start: function (event, ui) {
                    $(this).attr("index", index);
                    ui.helper.css("z-index", 200);
                    $(this).css("visibility", "hidden");
                },
                revert: "invalid",
            });
        });
        $(".slot").droppable({
            drop: function(event, ui) {
                var from = ui.draggable.attr("index");
                var to = $(this).attr("index");
                conn.queue('inventory-move', {
                    From: from,
                    To: to,
                });
                var $fromImg = ui.draggable;
                var $toImg = $(this).children("img");
                var fromSrc = $fromImg.attr("src");
                var toSrc = $toImg.attr("src");
                console.log(ui.draggable, fromSrc, toSrc);
                if (from === to || fromSrc == toSrc) {
                    ui.draggable.css("visibility", "visible");
                } else {
                    $fromImg.attr("src", toSrc);
                    $toImg.attr("src", fromSrc);
                    ui.draggable.load(function () {
                        ui.draggable.css("visibility", "visible");
                    });
                }
            },
        });
    }

    function updateHtmlEquipChanged(isLeft) {
        var side = isLeft ? "left" : "right";
        var primaryId = "#" + side + "Primary";
        var reserveId = "#" + side + "Reserve";
        if ((isLeft && leftIsPrimary) || (!isLeft && rightIsPrimary)) {
            $(primaryId).addClass("selected");
            $(reserveId).removeClass("selected");
        } else {
            $(primaryId).removeClass("selected");
            $(reserveId).addClass("selected");
        }
    }

    function updateHtmlItemIcons() {
        for (var y = 0; y < 5; y++) {
            for (var x = 0; x < 5; x++) {
                var index = y*5 + x;
                $("#bag" + index).children("img").attr("src", slots[index].icon());
            }
        }
        $("#leftPrimary").children("img").attr("src", slots[BAG_SIZE].icon());
        $("#leftReserve").children("img").attr("src", slots[BAG_SIZE + 1].icon());
        $("#rightPrimary").children("img").attr("src", slots[BAG_SIZE + 2].icon());
        $("#rightReserve").children("img").attr("src", slots[BAG_SIZE + 3].icon());
    }

    function updateEquipped(oldLeft, oldRight) {
        if (slots.length === 0) return;

        // Special case when switching left and right hands
        var skipModels = oldLeft != null
                      && oldRight != null
                      && oldLeft.model === rightItem().model
                      && oldRight.model === leftItem().model;

        if (!skipModels && oldLeft !== null) {
            swapModels(oldLeft, leftItem());
        }
        if (!skipModels && oldRight !== null) {
            swapModels(oldRight, rightItem());
        }

        conn.queue('inventory-state', {
            ItemLeft: getEquippedSlot(true, leftIsPrimary),
            ItemRight: getEquippedSlot(false, rightIsPrimary),
        });
    }

    function updateBagVisibility() {
        var $elm = $("#bag");
        if (bagIsShowing) {
            $elm.show();
            controls.unlock();
        } else {
            $elm.hide();
            controls.lock();
        }
    }

    function swapModels(oldItem, newItem) {
        if (oldItem.model !== null) {
            world.removeFromScene(oldItem.model);
        }
        var model = newItem.model;
        if (model !== null) {
            model.scale.set(1/16, 1/16, 1/16);
            world.addToScene(model);
        }
        return oldItem.type === newItem.type;
    }

    function pointItem(item, c) {
        var p = item.position;
        var target = new THREE.Vector3();
        target.x = p.x + sin(c.lat) * cos(c.lon);
        target.y = p.y + cos(c.lat);
        target.z = p.z + sin(c.lat) * sin(c.lon);
        item.lookAt(target);
    }

    function positionItem(item, playerPos, c) {
        var pp = playerPos;
        var ip = item.position;

        // http://www.vias.org/comp_geometry/math_coord_convert_3d.htm
        var theta = c.lat - 0.5;
        var phi = c.lon;
        var r = 0.15;
        var offset = sphericalToCartesian(r, theta, phi);
        ip.copy(pp).add(offset);
    }

    function sphericalToCartesian(r, theta, phi) {
        return new THREE.Vector3(
            r*sin(theta)*cos(phi),
            r*cos(theta),
            r*sin(theta)*sin(phi)
        );
    }

    function postitionPerspective(item, leftward) {
        var p = item.position;
        var r = new THREE.Matrix4();
        r.setRotationFromEuler(item.rotation, item.eulerOrder);

        var amount = leftward * aspectRatio * 0.05;

        // Move left / right
        var mov = new THREE.Vector3(amount, 0, 0);
        mov.applyMatrix3(r);

        p.add(mov);
    }

    var leftOffset = { x: Math.random(), z: Math.random() };
    var rightOffset = { x: Math.random(), z: Math.random() };
    function addJitter(item, values) {
        values.x += Math.random() / 30;
        values.z += Math.random() / 30;
        item.position.x += Math.sin(values.x) / 400;
        item.position.z += Math.sin(values.z) / 400;
    }

    var swapLeftWasDown = false;
    var swapRightWasDown = false;
    var toggleBagWasDown = false;
    self.update = function (playerPosition, controlState) {
        if (slots.length === 0) return;
        var p = playerPosition;
        var c = controlState;

        var leftWasDown = updateSide(true);
        var rightWasDown = updateSide(false);

        var toggleBagDown = c["toggleBag"];
        if (!toggleBagWasDown && toggleBagDown) {
            bagIsShowing = !bagIsShowing;
            updateBagVisibility();
        }
        toggleBagWasDown = toggleBagDown;

        swapLeftWasDown = leftWasDown;
        swapRightWasDown = rightWasDown;

        function activateItem(item) {
            var action = item.action();
            if (action) {
                action(world, camera);
            } else {
                console.log("Attempted to use an empty item slot.");
            }
        }

        function updateSide(isLeft) {
            var pos = isLeft ? 1 : -1;
            var offset = isLeft ? leftOffset : rightOffset;
            var swapWasDown = isLeft ? swapLeftWasDown : swapRightWasDown;
            var side = isLeft ? "Left" : "Right";
            var swapTrigger = "swap" + side;
            var activateTrigger = "activate" + side;
            var item = isLeft ? leftItem() : rightItem();
            var itemModel = item.model;

            if (itemModel !== null) {
                pointItem(itemModel, c);
                positionItem(itemModel, p, c);
                postitionPerspective(itemModel, pos);
                addJitter(itemModel, offset);
            }

            var swapDown = c[swapTrigger];
            if (!swapWasDown && swapDown) {
                if (isLeft) leftIsPrimary = !leftIsPrimary;
                else rightIsPrimary = !rightIsPrimary;
                updateEquipped((isLeft ? item : null),
                               (isLeft ? null : item));
                updateHtmlEquipChanged(isLeft);
            }

            if (c[activateTrigger]) {
                activateItem(item);
            }

            return swapDown;
        };
    };
}
<|endoftext|>


<commit_before>/* global console, Backbone, _, $ */
angular
	.module('indx')
	.factory('collection', function () {
		'use strict';

		var Model = function () {};
		Model.extend = function (obj) {
			/// @ignore -- TODO
			var _F = function () {};
			_F.prototype = _.extend({}, Model.prototype, obj);
			return _F;
		};
		_.extend(Model.prototype, {
			is_new: false,
			is_editing: false,
			is_selected: false,
			initialize: function () {},
			create: function () {
				var that = this;
				console.log('creating item');
				this.box.get_obj(this.id).then(function (new_obj) {
					console.log('new item');
					new_obj.save(that.newAttributes).then(function () {
						console.log('saved');
						that.trigger('created', new_obj);
					});
				});
				return this;
			},
			remove: function () {
				console.log('remove item', this);
				this.destroy().then(function () {
					console.log('destroyed item');
					//that.trigger('destroyed', this);
				});
			},
			edit: function (is_new) {
				console.log('edit item', this);
				this.newAttributes = _.clone(this.attributes);
				this.is_new = is_new;
				this.is_editing = true;
				this.trigger('edit');
				return this;
			},
			stage_and_save: function () {
				var that = this;
				console.log('stage and save');
				if (this.is_new) {
					console.log('new, so create');
					return this.create();
				} else {
					this.save(this.newAttributes).then(function () {
						console.log('saved');
						that.restore();
						// u.safe_apply($scope); TODO
					});
				}
			},
			save: function () {
				if (this.is_new) {
					console.warn('supressing save');
				} else {
					return Backbone.Model.prototype.save.apply(this, arguments);
				}
			},
			restore: function () {
				this.is_editing = false;
				this.trigger('restore');
				return this;
			},
			select: function (selected, options) {
				options = options || {};
				console.log('select', selected);
				selected = _.isBoolean(selected) ? selected : true;
				if (this.is_selected !== selected) {
					console.log('selecting', selected);
					this.is_selected = selected;
					this.trigger('select', selected, options);
				}
			}
		});
		var Collection = Backbone.Collection.extend({
			/// the collection.Model the cast each model to
			model: Model,
			selected: undefined,
			initialize: function (models, options) {
				var that = this;
				this.options = options || {};
				this.box = this.options.box;
				this.obj = this.options.obj;
				this.on('add remove', function () {
					console.log('something in the collection has changed');
					that.save();
				}).on('add remove reset', function () {
					that._set_new_model(that._new_model);
				});
				this.reset(models);
				this.populate();
				this._set_new_model();
			},
			///
			/// @opt <{}> attributes Attributes of new model
			/// @opt <{}> options
			///
			/// @return <model> Model inheriting collection.model
			///
			/// Make a new instance of the model. When the model is saved,
			/// it will be put in the box as an obj and appended to the array.
			new_model: function (attributes, options) {
				var that = this,
					model = new Backbone.Model(attributes);
				options = options || {};
				this._extend_model(model);
				model
					.edit(true)
					.set({ timestamp: now() })
					.on('created', function (model) {
						console.log('going for the add');
						that.add(model);
						that._set_new_model();
						if (options.select) { model.select(); }
						model.trigger('restore');
					})
					.on('restore', function () {
						that._set_new_model();
						if (options.select) { that.selected = undefined; }
					});
				this._set_new_model(model);
				if (options.select) { model.select(true, { save: false }); }
				return model;
			},
			_set_new_model: function (model) {
				this._new_model = model;
				this.all_models = model ? this.models.concat([ model ]) : this.models;
				this.filter();
				//console.log('update');
			},
			/// Remove the model from the array
			remove: function (model) {
				console.log('!!!remove!!!', arguments);
				if (this.selected === model) { this.selected = undefined; }
				return Backbone.Collection.prototype.remove.apply(this, arguments);
			},
			_extend_model: function (model) {
				var that = this,
					prototype = this.model.prototype;
				_.extend(model, prototype);
				if (prototype.initialize) {
					prototype.initialize.apply(model);
				}
				if (prototype.defaults) {
					_.defaults(model.attributes, prototype.defaults);
				}
				model.box = this.box;
				model.on('select', function (selected, options) {
					options = options || {};
					if (selected && that.selected === model) { return; }
					if (that.selected) { that.selected.select(false); }
					if (selected) {
						that.selected = model;
						that.trigger('select', model);
					}
					if (options.save !== false &&
							(that.options.save_selected || that.options.sync_selected)) {
						model.save({ selected: selected });
						that.each(function (m) {
							if (m !== model && pop(m.get('selected'))) {
								m.save({ selected: false });
							}
						});
					}
				}).on('restore', function () {
					that.trigger('update');
				});
				/*
				model.on('destroyed', function () { // TODO: unbind to prevent memory leaks
					console.log('detected destroy, removing model');
					that.remove(model);
				});*/
			},
			add: function (model, options) {
				var that = this;
				if (_.isArray(model)) {
					_.each(model, function (model) { that.add(model, options); });
				} else {
					if (!_.isObject(model)) {
						console.warn('There was a non-object stored??', model);
						return;
					}
					this._extend_model(model);
					if (this.options.save_selected || this.options.sync_selected) {
						if (pop(model.get('selected')) === true) {
							model.select();
						}
						if (this.options.sync_selected) {
							model.on('change:selected', function () {
								model.select(pop(model.get('selected')));
							});
						}
					}
					return Backbone.Collection.prototype.add.apply(this, arguments);
				}
			},
			/// Fetch the object and update the collection with models in the array
			fetch: function () {
				var that = this,
					promise = $.Deferred();
				this.obj.fetch().then(function () {
					that.populate();
					promise.resolve(that);
				});
				return promise;
			},
			/// Update the collection with models in the array. This will happen automatically when the array changes.
			populate: function () {
				if (!this.obj || !this.options.array_key) { return; }
				var that = this,
					obj = this.obj,
					array_key = this.options.array_key,
					arr = obj.get(array_key) || [];
				this.reset(arr);
				obj.on('change:' + array_key, function (obj, arr) {
					console.log('updating list -->', arguments);
					that.reset(arr);
				});
				//console.log('obj --> ', obj, array_key);
				//console.log('list --> ', arr);
			},
			/// Save the obj with the current array state. This will happen automatically when the array changes.
			save: function () {
				var that = this,
					promise = $.Deferred(),
					array_key = that.options.array_key;
				console.log('trying to save list = ', that.models);
				this.obj.save(array_key, that.models).then(function () {
					promise.resolve();
				}).fail(function () { promise.reject('Could not save'); });
				return promise;
			},
			filter: function (fn) {
				if (fn) { this._filter_fn = fn; }
				if (this._filter_fn) {
					this.filtered_models = _.filter(this.all_models, fn);
				} else {
					this.filtered_models = this.all_models;
				}
				this.trigger('update', this);
				return this;
			}
		});

		var now = function () {
			return (new Date()).valueOf();
		};
		var pop = function (arr) {
			if (!_.isArray(arr)) { return arr; }
			return _.first(arr);
		};

		return {
			Model: Model,
			Collection: Collection,
			now: now
		};

	});<commit_msg>fixed remove bug<commit_after>/* global console, Backbone, _, $ */
angular
	.module('indx')
	.factory('collection', function () {
		'use strict';

		var Model = function () {};
		Model.extend = function (obj) {
			/// @ignore -- TODO
			var _F = function () {};
			_F.prototype = _.extend({}, Model.prototype, obj);
			return _F;
		};
		_.extend(Model.prototype, {
			is_new: false,
			is_editing: false,
			is_selected: false,
			initialize: function () {},
			create: function () {
				var that = this;
				console.log('creating item');
				this.box.get_obj(this.id).then(function (new_obj) {
					console.log('new item');
					new_obj.save(that.newAttributes).then(function () {
						console.log('saved');
						that.trigger('created', new_obj);
					});
				});
				return this;
			},
			remove: function () {
				var that = this;
				console.log('remove item', this);
				this.destroy().then(function () {
					console.log('destroyed item');
					that.trigger('restore', this);
				});
			},
			edit: function (is_new) {
				console.log('edit item', this);
				this.newAttributes = _.clone(this.attributes);
				this.is_new = is_new;
				this.is_editing = true;
				this.trigger('edit');
				return this;
			},
			stage_and_save: function () {
				var that = this;
				console.log('stage and save');
				if (this.is_new) {
					console.log('new, so create');
					return this.create();
				} else {
					this.save(this.newAttributes).then(function () {
						console.log('saved');
						that.restore();
						// u.safe_apply($scope); TODO
					});
				}
			},
			save: function () {
				if (this.is_new) {
					console.warn('supressing save');
				} else {
					return Backbone.Model.prototype.save.apply(this, arguments);
				}
			},
			restore: function () {
				this.is_editing = false;
				this.trigger('restore');
				return this;
			},
			select: function (selected, options) {
				options = options || {};
				console.log('select', selected);
				selected = _.isBoolean(selected) ? selected : true;
				if (this.is_selected !== selected) {
					console.log('selecting', selected);
					this.is_selected = selected;
					this.trigger('select', selected, options);
				}
			}
		});
		var Collection = Backbone.Collection.extend({
			/// the collection.Model the cast each model to
			model: Model,
			selected: undefined,
			initialize: function (models, options) {
				var that = this;
				this.options = options || {};
				this.box = this.options.box;
				this.obj = this.options.obj;
				this.on('add remove', function () {
					console.log('something in the collection has changed');
					that.save();
				}).on('add remove reset', function () {
					that._set_new_model(that._new_model);
				});
				this.reset(models);
				this.populate();
				this._set_new_model();
			},
			///
			/// @opt <{}> attributes Attributes of new model
			/// @opt <{}> options
			///
			/// @return <model> Model inheriting collection.model
			///
			/// Make a new instance of the model. When the model is saved,
			/// it will be put in the box as an obj and appended to the array.
			new_model: function (attributes, options) {
				var that = this,
					model = new Backbone.Model(attributes);
				options = options || {};
				this._extend_model(model);
				model
					.edit(true)
					.set({ timestamp: now() })
					.on('created', function (model) {
						console.log('going for the add');
						that.add(model);
						that._set_new_model();
						if (options.select) { model.select(); }
						model.trigger('restore');
					})
					.on('restore', function () {
						that._set_new_model();
						if (options.select) { that.selected = undefined; }
					});
				this._set_new_model(model);
				if (options.select) { model.select(true, { save: false }); }
				return model;
			},
			_set_new_model: function (model) {
				this._new_model = model;
				this.all_models = model ? this.models.concat([ model ]) : this.models;
				this.filter();
				//console.log('update');
			},
			/// Remove the model from the array
			remove: function (model) {
				console.log('!!!remove!!!', arguments);
				if (this.selected === model) { this.selected = undefined; }
				return Backbone.Collection.prototype.remove.apply(this, arguments);
			},
			_extend_model: function (model) {
				var that = this,
					prototype = this.model.prototype;
				_.extend(model, prototype);
				if (prototype.initialize) {
					prototype.initialize.apply(model);
				}
				if (prototype.defaults) {
					_.defaults(model.attributes, prototype.defaults);
				}
				model.box = this.box;
				model.on('select', function (selected, options) {
					options = options || {};
					if (selected && that.selected === model) { return; }
					if (that.selected) { that.selected.select(false); }
					if (selected) {
						that.selected = model;
						that.trigger('select', model);
					}
					if (options.save !== false &&
							(that.options.save_selected || that.options.sync_selected)) {
						model.save({ selected: selected });
						that.each(function (m) {
							if (m !== model && pop(m.get('selected'))) {
								m.save({ selected: false });
							}
						});
					}
				}).on('restore', function () {
					that.trigger('update');
				});
				/*
				model.on('destroyed', function () { // TODO: unbind to prevent memory leaks
					console.log('detected destroy, removing model');
					that.remove(model);
				});*/
			},
			add: function (model, options) {
				var that = this;
				if (_.isArray(model)) {
					_.each(model, function (model) { that.add(model, options); });
				} else {
					if (!_.isObject(model)) {
						console.warn('There was a non-object stored??', model);
						return;
					}
					this._extend_model(model);
					if (this.options.save_selected || this.options.sync_selected) {
						if (pop(model.get('selected')) === true) {
							model.select();
						}
						if (this.options.sync_selected) {
							model.on('change:selected', function () {
								model.select(pop(model.get('selected')));
							});
						}
					}
					return Backbone.Collection.prototype.add.apply(this, arguments);
				}
			},
			/// Fetch the object and update the collection with models in the array
			fetch: function () {
				var that = this,
					promise = $.Deferred();
				this.obj.fetch().then(function () {
					that.populate();
					promise.resolve(that);
				});
				return promise;
			},
			/// Update the collection with models in the array. This will happen automatically when the array changes.
			populate: function () {
				if (!this.obj || !this.options.array_key) { return; }
				var that = this,
					obj = this.obj,
					array_key = this.options.array_key,
					arr = obj.get(array_key) || [];
				this.reset(arr);
				obj.on('change:' + array_key, function (obj, arr) {
					console.log('updating list -->', arguments);
					that.add(arr, { merge: true, silent: true });
					var ids = _.pluck(arr, 'id');
					that.remove(that.select(function (model) {
						return ids.indexOf(model.id) < 0;
					}), { silent: true });
					that.trigger('reset');
				});
				//console.log('obj --> ', obj, array_key);
				//console.log('list --> ', arr);
			},
			/// Save the obj with the current array state. This will happen automatically when the array changes.
			save: function () {
				var that = this,
					promise = $.Deferred(),
					array_key = that.options.array_key;
				console.log('trying to save list = ', that.models);
				this.obj.save(array_key, that.models).then(function () {
					promise.resolve();
				}).fail(function () { promise.reject('Could not save'); });
				return promise;
			},
			filter: function (fn) {
				if (fn) { this._filter_fn = fn; }
				if (this._filter_fn) {
					this.filtered_models = _.filter(this.all_models, fn);
				} else {
					this.filtered_models = this.all_models;
				}
				this.trigger('update', this);
				return this;
			}
		});

		var now = function () {
			return (new Date()).valueOf();
		};
		var pop = function (arr) {
			if (!_.isArray(arr)) { return arr; }
			return _.first(arr);
		};

		return {
			Model: Model,
			Collection: Collection,
			now: now
		};

	});<|endoftext|>


<commit_before>
    $j(document).ready(function()     {
        var idx = $j("#editIndex").attr("value");
        var editType = $j("#editType").attr("value");
        if (idx != undefined && idx != -1) {
            if (editType == 'active') {
                $j("#A"+idx).click();
                if ($j("#financialEntityHelper\\.activeFinancialEntities\\["+idx+"\\]\\.finEntityContactInfos\\[0\\]\\.countryCode").length > 0) {
                    var countryCode = $j("#financialEntityHelper\\.activeFinancialEntities\\["+idx+"\\]\\.finEntityContactInfos\\[0\\]\\.countryCode").val();
                    if (countryCode != '' && countryCode != 'USA') {
                       updateStateCode('financialEntityHelper.activeFinancialEntities['+idx+'].finEntityContactInfos[0].countryCode', '');
                    }
                }

                $j("#financialEntityHelper\\.activeFinancialEntities\\["+idx+"\\]\\.sponsorCode").focus(function() {
                    displayAlertMessage('messageBox'+idx, 'The entity address fields will be overriden when a valid sponsor code is entered');
                });
            } else {
                $j("#A"+idx+"i").click();
                if ($j("#financialEntityHelper\\.inactiveFinancialEntities\\["+idx+"\\]\\.finEntityContactInfos\\[0\\]\\.countryCode").length > 0) {
                    var countryCode = $j("#financialEntityHelper\\.inactiveFinancialEntities\\["+idx+"\\]\\.finEntityContactInfos\\[0\\]\\.countryCode").val();
                    if (countryCode != '' && countryCode != 'USA') {
                       updateStateCode('financialEntityHelper.inactiveFinancialEntities['+idx+'].finEntityContactInfos[0].countryCode', '');
                    }
                }

                $j("#financialEntityHelper\\.inactiveFinancialEntities\\["+idx+"\\]\\.sponsorCode").focus(function() {
                    displayAlertMessage('messageBox'+idx, 'The entity address fields will be overriden when a valid sponsor code is entered');
                });
            }
        }

        $j("#financialEntityHelper\\.newPersonFinancialEntity\\.sponsorCode").focus(function() {
            displayAlertMessage('messageBox', 'The entity address fields will be overriden when a valid sponsor code is entered');
          //return false;
        });

        if ($j("#financialEntityHelper\\.newPersonFinancialEntity\\.finEntityContactInfos\\[0\\]\\.countryCode").length > 0) {
             // ".length >0" check to make sure this element does exist
              var countryCode = $j("#financialEntityHelper\\.newPersonFinancialEntity\\.finEntityContactInfos\\[0\\]\\.countryCode").val();
              if (countryCode != '' && countryCode != 'USA') {
                  updateStateCode('financialEntityHelper.newPersonFinancialEntity.finEntityContactInfos[0].countryCode', '');
              }
        }

        $j('input[name^="methodToCall.performLookup.(!!org.kuali.kra.bo.Sponsor!!)"]').click(function() {
            if(!confirm('The entity address fields will be overriden when a valid sponsor is selected.  Do you want to continue ?')) {
                return false;
            }
        });

      // there are 2 different rows, one is the entity name/sponsor .. row, and the other row is
      // this history header row of the entity listed above.  However, the sorter can't distinguish them.
      // this widget is to reloacate the 'history row' back immediately following its belonging entity.
        $j.tablesorter.addWidget({
             // give the widget a id
            id: "relocaterow",
            // format is called when the on init and when a sorting has finished
            format: function(table) {

            // loop all tr elements and insert a copy of the "headers"
                for(var i=0; i
 1) {
                        var idx = $j(table.tBodies[0].rows[i]).attr("id").substring(6); // "hdrrowxx"
                        var tableRow = $j("#G"+idx);
                        $j(tableRow).insertAfter(table.tBodies[0].rows[i]);
                    }
                }
            }
        });

 // there is no proper parser for data/time field.  'shortDate is only for date'
 // add this parser for 'last update' column
        $j.tablesorter.addParser({
            id: "datetime",
            is: function(s) {
                return s.match(new RegExp(/^([0]\d|[1][0-2])\/([0-2]\d|[3][0-1])\/([2][01]|[1][6-9])\d{2}(\s([0]\d|[1][0-2])(\:[0-5]\d){1,2})*\s*([aApP][mM]{0,2})?$/));
            },
            format: function(s) {
                return $j.tablesorter.formatFloat(new Date(s).getTime());
            },
            type: "numeric"
        });

// call the tablesorter plugin and assign widgets with id "zebra" (Default widget in the core) and the newly created "relocaterow"

      $j("#activeEntities-table").tablesorter(

        // pass the headers argument and assing a object
         {  widgets: ['zebra','relocaterow'],
           // initial sort on 2nd column (entity name) on ascending order
            sortList: [[1,0]],
            // "header" is conflict with kuali-stylesheet.css; so
            cssHeader: "sorterheader",
            headers: {             // assign the first column (we start counting zero)
               0: {                 // disable it by setting the property sorter to false
                  sorter: false             },
               3: {sorter:'datetime' },
               4: {                 // disable it by setting the property sorter to false
                   sorter: false             }
                     }
          }
          );

      try {
      $j("#inActiveEntities-table").tablesorter(

           {  widgets: ['zebra','relocaterow'],
              sortList: [[1,0]],
            // "header" is conflict with kuali-stylesheet.css; so
            cssHeader: "sorterheader",
              headers: {             // assign the first column (we start counting zero)
                 0: {                 // disable it by setting the property sorter to false
                    sorter: false             },
                 3: {sorter:'datetime' },
                 4: {                 // disable it by setting the property sorter to false
                     sorter: false             }
                     }
            }
          );
     } catch (err) {
       // if inactive list is empty, then .ready skipped the rest of codes.  not sure why.
       // so use this try catch to keep it going.
       // alert("inactive table sorter has error "+err);
     }
           if ($j(".financialEntitySubpanel").length > 0) {
               $j(".financialEntitySubpanel").toggle(
                        function()
                        {
                            var controlId = $j(this).attr("id");
                            var contentId = controlId.replace("Control","Content");
                            $j("#"+contentId).slideDown(500);
                            $j(this).html("");
                        },function(){
                            var controlId = $j(this).attr("id");
                            var contentId = controlId.replace("Control","Content");
                            $j("#"+contentId).slideUp(500);
                            $j(this).html("");
                        }
               );
               $j(".financialEntitySubpanel").click();
           }

           $j(".relationDetailSubpanel").toggle(
                        function()
                        {
                            var controlId = $j(this).attr("id");
                            var contentId = controlId.replace("Control","Content");
                            $j("#"+contentId).slideDown(500);
                            $j(this).html("");
                        },function(){
                            var controlId = $j(this).attr("id");
                            var contentId = controlId.replace("Control","Content");
                            $j("#"+contentId).slideUp(500);
                            $j(this).html("");
                        }
               );
                $j(".relationDetailSubpanelContent").hide();

    } );  // end document.ready

    function displayAlertMessage(messagedivid, message) {
        var timeOut = 5
        $j('#'+messagedivid).text(message).fadeIn().css({"display":"block","color":"red"});
        setTimeout(function() {
            $j('#'+messagedivid).fadeOut().css("display", "none");
         }, timeOut * 1000);
    }

    function updateStateCode(countryCodeFieldName, state) {
    var stateField = findElPrefix( countryCodeFieldName )+".state";
    var countryCode = DWRUtil.getValue( countryCodeFieldName);

    var dwrReply = {
        callback:function(data) {
            if ( data != null ) {
                DWRUtil.removeAllOptions( stateField );
                $(stateField).options[0] = new Option('', '');
                DWRUtil.addOptions( stateField, data, 'postalStateCode', 'postalStateName' );
                if (state != '') {
                        DWRUtil.setValue(stateField, state);
                }
            }
        },
        errorHandler:function( errorMessage ) {
            window.status = errorMessage;
        }
    };

    StateService.findAllStatesByAltCountryCode(countryCode, dwrReply);
    }

    function loadEntityContactInfoFromRolodex(rolodexId, prefix) {
//        var rolodexId = DWRUtil.getValue( rolodexFieldName );

        if (rolodexId != '') {
            var dwrReply = {
                callback:function(data) {
                    if ( data != null ) {
                        DWRUtil.setValue(prefix+".addressLine1", data.addressLine1);
                        DWRUtil.setValue(prefix+".addressLine2", data.addressLine2);
                        DWRUtil.setValue(prefix+".addressLine3", data.addressLine3);
                        DWRUtil.setValue(prefix+".city", data.city);
                        DWRUtil.setValue(prefix+".countryCode", data.countryCode);
                        updateStateCode(prefix+".countryCode", data.state)
                        DWRUtil.setValue(prefix+".state", data.state);
                        DWRUtil.setValue(prefix+".postalCode", data.postalCode);
                    }
                },
                errorHandler:function( errorMessage ) {
                    window.status = errorMessage;
                }
            };
            RolodexService.getRolodex(rolodexId, dwrReply);
        }

}
    <commit_msg>kccoi-9<commit_after>
    $j(document).ready(function()     {
        var idx = $j("#editIndex").attr("value");
        var editType = $j("#editType").attr("value");
        if (idx != undefined && idx != -1) {
            if (editType == 'active') {
                $j("#A"+idx).click();
                if ($j("#financialEntityHelper\\.activeFinancialEntities\\["+idx+"\\]\\.finEntityContactInfos\\[0\\]\\.countryCode").length > 0) {
                    var countryCode = $j("#financialEntityHelper\\.activeFinancialEntities\\["+idx+"\\]\\.finEntityContactInfos\\[0\\]\\.countryCode").val();
                    if (countryCode != '' && countryCode != 'USA') {
                       updateStateCode('financialEntityHelper.activeFinancialEntities['+idx+'].finEntityContactInfos[0].countryCode', '');
                    }
                }

                $j("#financialEntityHelper\\.activeFinancialEntities\\["+idx+"\\]\\.sponsorCode").focus(function() {
                    displayAlertMessage('messageBox'+idx, 'The entity address fields will be overriden when a valid sponsor code is entered');
                });
            } else {
                $j("#A"+idx+"i").click();
                if ($j("#financialEntityHelper\\.inactiveFinancialEntities\\["+idx+"\\]\\.finEntityContactInfos\\[0\\]\\.countryCode").length > 0) {
                    var countryCode = $j("#financialEntityHelper\\.inactiveFinancialEntities\\["+idx+"\\]\\.finEntityContactInfos\\[0\\]\\.countryCode").val();
                    if (countryCode != '' && countryCode != 'USA') {
                       updateStateCode('financialEntityHelper.inactiveFinancialEntities['+idx+'].finEntityContactInfos[0].countryCode', '');
                    }
                }

                $j("#financialEntityHelper\\.inactiveFinancialEntities\\["+idx+"\\]\\.sponsorCode").focus(function() {
                    displayAlertMessage('messageBox'+idx, 'The entity address fields will be overriden when a valid sponsor code is entered');
                });
            }
        }

        $j("#financialEntityHelper\\.newPersonFinancialEntity\\.sponsorCode").focus(function() {
            displayAlertMessage('messageBox', 'The entity address fields will be overriden when a valid sponsor code is entered');
          //return false;
        });

        if ($j("#financialEntityHelper\\.newPersonFinancialEntity\\.finEntityContactInfos\\[0\\]\\.countryCode").length > 0) {
             // ".length >0" check to make sure this element does exist
              var countryCode = $j("#financialEntityHelper\\.newPersonFinancialEntity\\.finEntityContactInfos\\[0\\]\\.countryCode").val();
              if (countryCode != '' && countryCode != 'USA') {
                  updateStateCode('financialEntityHelper.newPersonFinancialEntity.finEntityContactInfos[0].countryCode', '');
              }
        }

        $j('input[name^="methodToCall.performLookup.(!!org.kuali.kra.bo.Sponsor!!)"]').click(function() {
            if(!confirm('The entity address fields will be overriden when a valid sponsor is selected.  Do you want to continue ?')) {
                return false;
            }
        });

      // there are 2 different rows, one is the entity name/sponsor .. row, and the other row is
      // this history header row of the entity listed above.  However, the sorter can't distinguish them.
      // this widget is to reloacate the 'history row' back immediately following its belonging entity.
        $j.tablesorter.addWidget({
             // give the widget a id
            id: "relocaterow",
            // format is called when the on init and when a sorting has finished
            format: function(table) {

            // loop all tr elements and insert a copy of the "headers"
                for(var i=0; i
 1) {
                        var idx = $j(table.tBodies[0].rows[i]).attr("id").substring(6); // "hdrrowxx"
                        var tableRow = $j("#G"+idx);
                        $j(tableRow).insertAfter(table.tBodies[0].rows[i]);
                    }
                }
            }
        });

 // there is no proper parser for data/time field.  'shortDate is only for date'
 // add this parser for 'last update' column
        $j.tablesorter.addParser({
            id: "datetime",
            is: function(s) {
                return s.match(new RegExp(/^([0]\d|[1][0-2])\/([0-2]\d|[3][0-1])\/([2][01]|[1][6-9])\d{2}(\s([0]\d|[1][0-2])(\:[0-5]\d){1,2})*\s*([aApP][mM]{0,2})?$/));
            },
            format: function(s) {
                return $j.tablesorter.formatFloat(new Date(s).getTime());
            },
            type: "numeric"
        });

// call the tablesorter plugin and assign widgets with id "zebra" (Default widget in the core) and the newly created "relocaterow"

      try {
      $j("#activeEntities-table").tablesorter(

        // pass the headers argument and assing a object
         {  widgets: ['zebra','relocaterow'],
           // initial sort on 2nd column (entity name) on ascending order
            sortList: [[1,0]],
            // "header" is conflict with kuali-stylesheet.css; so
            cssHeader: "sorterheader",
            headers: {             // assign the first column (we start counting zero)
               0: {                 // disable it by setting the property sorter to false
                  sorter: false             },
               3: {sorter:'datetime' },
               4: {                 // disable it by setting the property sorter to false
                   sorter: false             }
                     }
          }
          );
     } catch (err) {
       // if active list is empty, then .ready skipped the rest of codes.  not sure why.
       // so use this try catch to keep it going.
     }

      try {
      $j("#inActiveEntities-table").tablesorter(

           {  widgets: ['zebra','relocaterow'],
              sortList: [[1,0]],
            // "header" is conflict with kuali-stylesheet.css; so
            cssHeader: "sorterheader",
              headers: {             // assign the first column (we start counting zero)
                 0: {                 // disable it by setting the property sorter to false
                    sorter: false             },
                 3: {sorter:'datetime' },
                 4: {                 // disable it by setting the property sorter to false
                     sorter: false             }
                     }
            }
          );
     } catch (err) {
       // if inactive list is empty, then .ready skipped the rest of codes.  not sure why.
       // so use this try catch to keep it going.
       // alert("inactive table sorter has error "+err);
     }
           if ($j(".financialEntitySubpanel").length > 0) {
               $j(".financialEntitySubpanel").toggle(
                        function()
                        {
                            var controlId = $j(this).attr("id");
                            var contentId = controlId.replace("Control","Content");
                            $j("#"+contentId).slideDown(500);
                            $j(this).html("");
                        },function(){
                            var controlId = $j(this).attr("id");
                            var contentId = controlId.replace("Control","Content");
                            $j("#"+contentId).slideUp(500);
                            $j(this).html("");
                        }
               );
               $j(".financialEntitySubpanel").click();
           }

           $j(".relationDetailSubpanel").toggle(
                        function()
                        {
                            var controlId = $j(this).attr("id");
                            var contentId = controlId.replace("Control","Content");
                            $j("#"+contentId).slideDown(500);
                            $j(this).html("");
                        },function(){
                            var controlId = $j(this).attr("id");
                            var contentId = controlId.replace("Control","Content");
                            $j("#"+contentId).slideUp(500);
                            $j(this).html("");
                        }
               );
                $j(".relationDetailSubpanelContent").hide();

    } );  // end document.ready

    function displayAlertMessage(messagedivid, message) {
        var timeOut = 5
        $j('#'+messagedivid).text(message).fadeIn().css({"display":"block","color":"red"});
        setTimeout(function() {
            $j('#'+messagedivid).fadeOut().css("display", "none");
         }, timeOut * 1000);
    }

    function updateStateCode(countryCodeFieldName, state) {
    var stateField = findElPrefix( countryCodeFieldName )+".state";
    var countryCode = DWRUtil.getValue( countryCodeFieldName);

    var dwrReply = {
        callback:function(data) {
            if ( data != null ) {
                DWRUtil.removeAllOptions( stateField );
                $(stateField).options[0] = new Option('', '');
                DWRUtil.addOptions( stateField, data, 'postalStateCode', 'postalStateName' );
                if (state != '') {
                        DWRUtil.setValue(stateField, state);
                }
            }
        },
        errorHandler:function( errorMessage ) {
            window.status = errorMessage;
        }
    };

    StateService.findAllStatesByAltCountryCode(countryCode, dwrReply);
    }

    function loadEntityContactInfoFromRolodex(rolodexId, prefix) {
//        var rolodexId = DWRUtil.getValue( rolodexFieldName );

        if (rolodexId != '') {
            var dwrReply = {
                callback:function(data) {
                    if ( data != null ) {
                        DWRUtil.setValue(prefix+".addressLine1", data.addressLine1);
                        DWRUtil.setValue(prefix+".addressLine2", data.addressLine2);
                        DWRUtil.setValue(prefix+".addressLine3", data.addressLine3);
                        DWRUtil.setValue(prefix+".city", data.city);
                        DWRUtil.setValue(prefix+".countryCode", data.countryCode);
                        updateStateCode(prefix+".countryCode", data.state)
                        DWRUtil.setValue(prefix+".state", data.state);
                        DWRUtil.setValue(prefix+".postalCode", data.postalCode);
                    }
                },
                errorHandler:function( errorMessage ) {
                    window.status = errorMessage;
                }
            };
            RolodexService.getRolodex(rolodexId, dwrReply);
        }

}
    <|endoftext|>


<commit_before>var NRS = (function(NRS, $, undefined) {
	NRS.loadContacts = function() {
		NRS.contacts = {};

		NRS.database.select("contacts", null, function(error, contacts) {
			if (contacts.length) {
				$.each(contacts, function(index, contact) {
					NRS.contacts[contact.accountId] = contact;
				});
			}
		});
	}

	NRS.pages.contacts = function() {
		NRS.pageLoading();

		if (!NRS.databaseSupport) {
			$("#contact_page_database_error").show();
			$("#contacts_table_container").hide();
			$("#add_contact_button").hide();
			NRS.pageLoaded();
			return;
		}

		$("#contacts_table_container").show();
		$("#contact_page_database_error").hide();

		NRS.database.select("contacts", null, function(error, contacts) {
			if (contacts.length) {
				var rows = "";

				contacts.sort(function(a, b) {
					if (a.name.toLowerCase() > b.name.toLowerCase()) {
						return 1;
					} else if (a.name.toLowerCase()  100) {
						contactDescription = contactDescription.substring(0, 100) + "...";
					} else if (!contactDescription) {
						contactDescription = "-";
					}

					rows += "
" + contact.name.escapeHTML() + "	" + NRS.getAccountFormatted(contact, "account") + "	" + (contact.email ? contact.email.escapeHTML() : "-") + "	" + contactDescription.escapeHTML() + "	Send Nxt Message Delete
";
				});

				$("#contacts_table tbody").empty().append(rows);
				NRS.dataLoadFinished($("#contacts_table"));

				NRS.pageLoaded();
			} else {
				$("#contacts_table tbody").empty();
				NRS.dataLoadFinished($("#contacts_table"));

				NRS.pageLoaded();
			}
		});
	}

	NRS.forms.addContact = function($modal) {
		var data = NRS.getFormData($modal.find("form:first"));

		if (!data.name) {
			return {
				"error": "Contact name is a required field."
			};
		} else if (!data.account_id) {
			return {
				"error": "Account ID is a required field."
			};
		}

		if (/^\d+$/.test(data.name) || /^NXT\-/i.test(data.name)) {
			return {
				"error": "Contact name must contain alphabetic characters."
			};
		}

		if (data.account_id.charAt(0) == '@') {
			var convertedAccountId = $modal.find("input[name=converted_account_id]").val();
			if (convertedAccountId) {
				data.account_id = convertedAccountId;
			} else {
				return {
					"error": "Invalid account ID."
				};
			}
		}

		NRS.sendRequest("getAccount", {
			"account": data.account_id
		}, function(response) {
			var $btn = $modal.find("button.btn-primary:not([data-dismiss=modal], .ignore)");

			var dbKey = (/^NXT\-/i.test(data.account_id) ? "accountRS" : "account");

			var dbQuery = {};
			dbQuery[dbKey] = data.account_id;

			NRS.database.select("contacts", [dbQuery], function(error, contacts) {
				if (contacts.length) {
					$modal.find(".error_message").html("A contact with this account ID already exists.").show();
					$btn.button("reset");
					$modal.modal("unlock");
				} else {
					NRS.database.insert("contacts", {
						name: data.name,
						email: data.email,
						account: response.account,
						accountRS: response.accountRS,
						description: data.description
					}, function(error) {
						NRS.contacts[response.account] = {
							name: data.name,
							email: data.email,
							account: response.account,
							accountRS: response.accountRS,
							description: data.description
						};

						$btn.button("reset");
						$modal.modal("unlock");
						$modal.modal("hide");
						$.growl("Contact added successfully.", {
							"type": "success"
						});

						if (NRS.currentPage == "contacts") {
							NRS.pages.contacts();
						} else if (NRS.currentPage == "messages" && NRS.selectedContext) {
							var heading = NRS.selectedContext.find("h4.list-group-item-heading");
							if (heading.length) {
								heading.html(data.name.escapeHTML());
							}
							NRS.selectedContext.data("context", "messages_sidebar_update_context");
						}
					});
				}
			});
		});

		return {
			"stop": true
		};
	}

	$("#update_contact_modal").on('show.bs.modal', function(e) {
		var $invoker = $(e.relatedTarget);

		var contactId = parseInt($invoker.data("contact"), 10);

		if (!contactId && NRS.selectedContext) {
			var accountId = NRS.selectedContext.data("account");

			var dbKey = (/^NXT\-/i.test(accountId) ? "accountRS" : "account");

			var dbQuery = {};
			dbQuery[dbKey] = accountId;

			NRS.database.select("contacts", [dbQuery], function(error, contact) {
				contact = contact[0];

				$("#update_contact_id").val(contact.id);
				$("#update_contact_name").val(contact.name);
				$("#update_contact_email").val(contact.email);
				if (NRS.settings["use_reed_solomon"]) {
					$("#update_contact_account_id").val(contact.accountRS);
				} else {
					$("#update_contact_account_id").val(contact.account);
				}
				$("#update_contact_description").val(contact.description);
			});
		} else {
			$("#update_contact_id").val(contactId);

			NRS.database.select("contacts", [{
				"id": contactId
			}], function(error, contact) {
				contact = contact[0];

				$("#update_contact_name").val(contact.name);
				$("#update_contact_email").val(contact.email);
				if (NRS.settings["use_reed_solomon"]) {
					$("#update_contact_account_id").val(contact.accountRS);
				} else {
					$("#update_contact_account_id").val(contact.account);
				}
				$("#update_contact_description").val(contact.description);
			});
		}
	});

	NRS.forms.updateContact = function($modal) {
		var data = NRS.getFormData($modal.find("form:first"));

		if (!data.name) {
			return {
				"error": "Contact name is a required field."
			};
		} else if (!data.account_id) {
			return {
				"error": "Account ID is a required field."
			};
		}

		if (data.account_id.charAt(0) == '@') {
			var convertedAccountId = $modal.find("input[name=converted_account_id]").val();
			if (convertedAccountId) {
				data.account_id = convertedAccountId;
			} else {
				return {
					"error": "Invalid account ID."
				};
			}
		}

		var contactId = parseInt($("#update_contact_id").val(), 10);

		if (!contactId) {
			return {
				"error": "Invalid contact."
			};
		}

		NRS.sendRequest("getAccount", {
			"account": data.account_id
		}, function(response) {
			var $btn = $modal.find("button.btn-primary:not([data-dismiss=modal])");

			var dbKey = (/^NXT\-/i.test(data.account_id) ? "accountRS" : "account");

			var dbQuery = {};
			dbQuery[dbKey] = data.account_id;

			NRS.database.select("contacts", [dbQuery], function(error, contacts) {
				if (contacts.length && contacts[0].id != contactId) {
					$modal.find(".error_message").html("A contact with this account ID already exists.").show();
					$btn.button("reset");
					$modal.modal("unlock");
				} else {
					NRS.database.update("contacts", {
						name: data.name,
						email: data.email,
						account: response.account,
						accountRS: response.accountRS,
						description: data.description
					}, [{
						"id": contactId
					}], function(error) {
						if (contacts.length && data.account_id != contacts[0].accountId) {
							delete NRS.contacts[contacts[0].accountId];
						}

						NRS.contacts[data.account_id] = {
							name: data.name,
							email: data.email,
							accountId: data.account_id,
							description: data.description
						};

						$btn.button("reset");
						$modal.modal("unlock");
						$modal.modal("hide");
						$.growl("Contact updated successfully.", {
							"type": "success"
						});

						if (NRS.currentPage == "contacts") {
							NRS.pages.contacts();
						} else if (NRS.currentPage == "messages" && NRS.selectedContext) {
							var heading = NRS.selectedContext.find("h4.list-group-item-heading");
							if (heading.length) {
								heading.html(data.name.escapeHTML());
							}
						}
					});
				}
			});
		});

		return {
			"stop": true
		};
	}

	$("#delete_contact_modal").on('show.bs.modal', function(e) {
		var $invoker = $(e.relatedTarget);

		var contactId = $invoker.data("contact");

		$("#delete_contact_id").val(contactId);

		NRS.database.select("contacts", [{
			"id": contactId
		}], function(error, contact) {
			contact = contact[0];

			$("#delete_contact_name").html(contact.name.escapeHTML());
			$("#delete_contact_account_id").val(contact.accountId);
		});
	});

	NRS.forms.deleteContact = function($modal) {
		var id = parseInt($("#delete_contact_id").val(), 10);

		NRS.database.delete("contacts", [{
			"id": id
		}], function() {
			delete NRS.contacts[$("#delete_contact_account_id").val()];

			$.growl("Contact deleted successfully.", {
				"type": "success"
			});

			if (NRS.currentPage == "contacts") {
				NRS.pages.contacts();
			}
		});

		return {
			"stop": true
		};
	}

	return NRS;
}(NRS || {}, jQuery));<commit_msg>RS contact page.<commit_after>var NRS = (function(NRS, $, undefined) {
	NRS.loadContacts = function() {
		NRS.contacts = {};

		NRS.database.select("contacts", null, function(error, contacts) {
			if (contacts.length) {
				$.each(contacts, function(index, contact) {
					NRS.contacts[contact.accountId] = contact;
				});
			}
		});
	}

	NRS.pages.contacts = function() {
		NRS.pageLoading();

		if (!NRS.databaseSupport) {
			$("#contact_page_database_error").show();
			$("#contacts_table_container").hide();
			$("#add_contact_button").hide();
			NRS.pageLoaded();
			return;
		}

		$("#contacts_table_container").show();
		$("#contact_page_database_error").hide();

		NRS.database.select("contacts", null, function(error, contacts) {
			if (contacts.length) {
				var rows = "";

				contacts.sort(function(a, b) {
					if (a.name.toLowerCase() > b.name.toLowerCase()) {
						return 1;
					} else if (a.name.toLowerCase()  100) {
						contactDescription = contactDescription.substring(0, 100) + "...";
					} else if (!contactDescription) {
						contactDescription = "-";
					}

					rows += "
" + contact.name.escapeHTML() + "	" + NRS.getAccountFormatted(contact, "account") + "	" + (contact.email ? contact.email.escapeHTML() : "-") + "	" + contactDescription.escapeHTML() + "	Send Nxt Message Delete
";
				});

				$("#contacts_table tbody").empty().append(rows);
				NRS.dataLoadFinished($("#contacts_table"));

				NRS.pageLoaded();
			} else {
				$("#contacts_table tbody").empty();
				NRS.dataLoadFinished($("#contacts_table"));

				NRS.pageLoaded();
			}
		});
	}

	NRS.forms.addContact = function($modal) {
		var data = NRS.getFormData($modal.find("form:first"));

		data.account_id = String(data.account_id);

		if (!data.name) {
			return {
				"error": "Contact name is a required field."
			};
		} else if (!data.account_id) {
			return {
				"error": "Account ID is a required field."
			};
		}

		if (/^\d+$/.test(data.name) || /^NXT\-/i.test(data.name)) {
			return {
				"error": "Contact name must contain alphabetic characters."
			};
		}

		if (data.email && !/@/.test(data.email)) {
			return {
				"error": "Email address is incorrect."
			};
		}

		if (data.account_id.charAt(0) == '@') {
			var convertedAccountId = $modal.find("input[name=converted_account_id]").val();
			if (convertedAccountId) {
				data.account_id = convertedAccountId;
			} else {
				return {
					"error": "Invalid account ID."
				};
			}
		}

		if (/^NXT\-/i.test(data.account_id)) {
			data.account_rs = data.account_id;

			var address = new NxtAddress();

			if (address.set(data.account_rs)) {
				data.account = address.account_id();
			} else {
				return {
					"error": "Invalid account ID."
				};
			}
		} else {
			var address = new NxtAddress();

			if (address.set(data.account_id)) {
				data.account_rs = address.toString();
			} else {
				return {
					"error": "Invalid account ID."
				};
			}
		}

		NRS.sendRequest("getAccount", {
			"account": data.account_id
		}, function(response) {
			if (!response.errorCode) {
				if (response.account != data.account || response.accountRS != data.account_rs) {
					return {
						"error": "Invalid account ID."
					};
				}
			}
		}, false);

		var $btn = $modal.find("button.btn-primary:not([data-dismiss=modal], .ignore)");

		NRS.database.select("contacts", [{
			"account": data.account_id
		}, {
			"name": data.name
		}], function(error, contacts) {
			if (contacts.length) {
				if (contacts[0].name == data.name) {
					$modal.find(".error_message").html("A contact with this name already exists.").show();
				} else {
					$modal.find(".error_message").html("A contact with this account ID already exists.").show();
				}
				$btn.button("reset");
				$modal.modal("unlock");
			} else {
				NRS.database.insert("contacts", {
					name: data.name,
					email: data.email,
					account: data.account_id,
					accountRS: data.account_rs,
					description: data.description
				}, function(error) {
					NRS.contacts[data.account_id] = {
						name: data.name,
						email: data.email,
						account: data.account_id,
						accountRS: data.account_rs,
						description: data.description
					};

					$btn.button("reset");
					$modal.modal("unlock");
					$modal.modal("hide");
					$.growl("Contact added successfully.", {
						"type": "success"
					});

					if (NRS.currentPage == "contacts") {
						NRS.pages.contacts();
					} else if (NRS.currentPage == "messages" && NRS.selectedContext) {
						var heading = NRS.selectedContext.find("h4.list-group-item-heading");
						if (heading.length) {
							heading.html(data.name.escapeHTML());
						}
						NRS.selectedContext.data("context", "messages_sidebar_update_context");
					}
				});
			}
		});
	}

	$("#update_contact_modal").on('show.bs.modal', function(e) {
		var $invoker = $(e.relatedTarget);

		var contactId = parseInt($invoker.data("contact"), 10);

		if (!contactId && NRS.selectedContext) {
			var accountId = NRS.selectedContext.data("account");

			var dbKey = (/^NXT\-/i.test(accountId) ? "accountRS" : "account");

			var dbQuery = {};
			dbQuery[dbKey] = accountId;

			NRS.database.select("contacts", [dbQuery], function(error, contact) {
				contact = contact[0];

				$("#update_contact_id").val(contact.id);
				$("#update_contact_name").val(contact.name);
				$("#update_contact_email").val(contact.email);
				if (NRS.settings["use_reed_solomon"]) {
					$("#update_contact_account_id").val(contact.accountRS);
				} else {
					$("#update_contact_account_id").val(contact.account);
				}
				$("#update_contact_description").val(contact.description);
			});
		} else {
			$("#update_contact_id").val(contactId);

			NRS.database.select("contacts", [{
				"id": contactId
			}], function(error, contact) {
				contact = contact[0];

				$("#update_contact_name").val(contact.name);
				$("#update_contact_email").val(contact.email);
				if (NRS.settings["use_reed_solomon"]) {
					$("#update_contact_account_id").val(contact.accountRS);
				} else {
					$("#update_contact_account_id").val(contact.account);
				}
				$("#update_contact_description").val(contact.description);
			});
		}
	});

	NRS.forms.updateContact = function($modal) {
		var data = NRS.getFormData($modal.find("form:first"));

		data.account_id = String(data.account_id);

		if (!data.name) {
			return {
				"error": "Contact name is a required field."
			};
		} else if (!data.account_id) {
			return {
				"error": "Account ID is a required field."
			};
		}

		if (data.account_id.charAt(0) == '@') {
			var convertedAccountId = $modal.find("input[name=converted_account_id]").val();
			if (convertedAccountId) {
				data.account_id = convertedAccountId;
			} else {
				return {
					"error": "Invalid account ID."
				};
			}
		}

		var contactId = parseInt($("#update_contact_id").val(), 10);

		if (!contactId) {
			return {
				"error": "Invalid contact."
			};
		}

		if (/^NXT\-/i.test(data.account_id)) {
			data.account_rs = data.account_id;

			var address = new NxtAddress();

			if (address.set(data.account_rs)) {
				data.account = address.account_id();
			} else {
				return {
					"error": "Invalid account ID."
				};
			}
		} else {
			var address = new NxtAddress();

			if (address.set(data.account_id)) {
				data.account_rs = address.toString();
			} else {
				return {
					"error": "Invalid account ID."
				};
			}
		}

		NRS.sendRequest("getAccount", {
			"account": data.account_id
		}, function(response) {
			if (!response.errorCode) {
				if (response.account != data.account || response.accountRS != data.account_rs) {
					return {
						"error": "Invalid account ID."
					};
				}
			}
		}, false);

		var $btn = $modal.find("button.btn-primary:not([data-dismiss=modal])");

		NRS.database.select("contacts", [{
			"account": data.account_id
		}], function(error, contacts) {
			if (contacts.length && contacts[0].id != contactId) {
				$modal.find(".error_message").html("A contact with this account ID already exists.").show();
				$btn.button("reset");
				$modal.modal("unlock");
			} else {
				NRS.database.update("contacts", {
					name: data.name,
					email: data.email,
					account: data.account_id,
					accountRS: data.account_rs,
					description: data.description
				}, [{
					"id": contactId
				}], function(error) {
					if (contacts.length && data.account_id != contacts[0].accountId) {
						delete NRS.contacts[contacts[0].accountId];
					}

					NRS.contacts[data.account_id] = {
						name: data.name,
						email: data.email,
						account: data.account_id,
						accountRS: data.account_rs,
						description: data.description
					};

					$btn.button("reset");
					$modal.modal("unlock");
					$modal.modal("hide");
					$.growl("Contact updated successfully.", {
						"type": "success"
					});

					if (NRS.currentPage == "contacts") {
						NRS.pages.contacts();
					} else if (NRS.currentPage == "messages" && NRS.selectedContext) {
						var heading = NRS.selectedContext.find("h4.list-group-item-heading");
						if (heading.length) {
							heading.html(data.name.escapeHTML());
						}
					}
				});
			}
		});
	}

	$("#delete_contact_modal").on('show.bs.modal', function(e) {
		var $invoker = $(e.relatedTarget);

		var contactId = $invoker.data("contact");

		$("#delete_contact_id").val(contactId);

		NRS.database.select("contacts", [{
			"id": contactId
		}], function(error, contact) {
			contact = contact[0];

			$("#delete_contact_name").html(contact.name.escapeHTML());
			$("#delete_contact_account_id").val(contact.accountId);
		});
	});

	NRS.forms.deleteContact = function($modal) {
		var id = parseInt($("#delete_contact_id").val(), 10);

		NRS.database.delete("contacts", [{
			"id": id
		}], function() {
			delete NRS.contacts[$("#delete_contact_account_id").val()];

			$.growl("Contact deleted successfully.", {
				"type": "success"
			});

			if (NRS.currentPage == "contacts") {
				NRS.pages.contacts();
			}
		});

		return {
			"stop": true
		};
	}

	return NRS;
}(NRS || {}, jQuery));<|endoftext|>