<commit_before>var Profile = {
	avatar: function (user, height) {
	    return '';
	},

	customAvatar: function (user, height) {
	    return '
';
	},

	name: function (user) {
	    return '' + user.name + '';
	},

	unregisteredName: function (user) {
	    return '' + user.name + ' (Unregistered)
';
	},

	rank: function (user) {
		return Utilities.rank(user);
	},

	elo: function (user) {
		io.stdinNumber('db/elo.csv', user, 'elo');
		if (user.elo === 0) {
			user.elo = 1000;
		}
		return ' | Elo Ranking: ' + Math.round(user.elo) + '
';
	},

	views: function (user) {
	    io.stdinNumber('db/views.csv', user, 'views');
	    var space = '      ';
	    return space + '- Views: ' + user.views;
	},

	money: function (user) {
	    io.stdinNumber('db/money.csv', user, 'money');
	    return 'Money: ' + '' + user.money;
	},

	tourWins: function (user) {
		io.stdinNumber('db/tourWins.csv', user, 'tourWins');
		return  ' | Tournament Wins: ' + user.tourWins + '
';
	},

	status: function (user) {
	    io.stdinString('db/status.csv', user, 'status');
	    if (user.status === '') {
	        user.status = 'This user hasn\'t set their status yet.';
	    }
	    return 'Status: "' + user.status + '"';
	},

	statusTime: function (user) {
	    io.stdinString('db/statusTime.csv', user, 'statusTime');
	    return ' ' + user.statusTime + '';
	}
};

var cmds = {
	profile: function (target, room, user, connection) {
	    if (!this.canBroadcast()) return;

	    var targetUser = this.targetUserOrSelf(target);

	    if (!targetUser) return this.sendReply('User ' + this.targetUsername + ' not found.');

	    var height = 75;

	    io.stdoutNumber('db/views.csv', targetUser, 'views', 1);

	     var display = Profile.avatar(targetUser, height) + Profile.name(targetUser) + Profile.views(targetUser) + '
' + Profile.rank(targetUser) + Profile.elo(targetUser) + Profile.money(targetUser) + Profile.tourWins(targetUser) + Profile.status(targetUser) + Profile.statusTime(targetUser);

	    if (!targetUser.authenticated) {
	        display = Profile.avatar(targetUser, height) + Profile.unregisteredName(targetUser) + Profile.views(targetUser) + '
' + Profile.rank(targetUser) + Profile.elo(targetUser) + Profile.money(targetUser) + Profile.tourWins(targetUser) + Profile.status(targetUser) + Profile.statusTime(targetUser);
	        return this.sendReplyBox(display);
	    } else if (typeof (targetUser.avatar) === typeof ('')) {
	        display = Profile.avatar(targetUser, height) + Profile.unregisteredName(targetUser) + Profile.views(targetUser) + '
' + Profile.rank(targetUser) + Profile.elo(targetUser) + Profile.money(targetUser) + Profile.tourWins(targetUser) + Profile.status(targetUser) + Profile.statusTime(targetUser);
	        return this.sendReplyBox(display);
	    } else {
	        return this.sendReplyBox(display);
	    }
	},

	setstatus: 'status',
	status: function(target, room, user){
		if (!target) return this.sendReply('|raw|Set your status for profile. Usage: /status status information');
		if (target.length > 30) return this.sendReply('Status is too long.');
		if (target.indexOf(',') >= 1) return this.sendReply('Unforunately, your status cannot contain a comma.');
		var escapeHTML = sanitize(target, true);
		io.stdoutString('db/status.csv', user, 'status', escapeHTML);

		var currentdate = new Date();
		var datetime = "Last Updated: " + (currentdate.getMonth()+1) + "/"+currentdate.getDate() + "/" + currentdate.getFullYear() + " @ "  + Utilities.formatAMPM(currentdate);
		io.stdoutString('db/statusTime.csv', user, 'statusTime', datetime);

		this.sendReply('Your status is now: "' + target + '"');
		if('+%@&~'.indexOf(user.group) >= 0) {
			room.add('|raw| * ' + user.name + ' set their status to: "' + escapeHTML + '"');
		}
	},
};

Object.merge(CommandParser.commands, cmds);
exports.cmds = cmds;
<commit_msg>Update profile.js<commit_after>var Profile = {
	avatar: function (user, height) {
	    return '';
	},

	customAvatar: function (user, height) {
	    return '
';
	},

	name: function (user) {
	    return '' + user.name + '';
	},

	unregisteredName: function (user) {
	    return '' + user.name + ' (Unregistered)';
	},

	rank: function (user) {
		return Utilities.rank(user);
	},

	elo: function (user) {
		io.stdinNumber('db/elo.csv', user, 'elo');
		if (user.elo === 0) {
			user.elo = 1000;
		}
		return ' | Elo Ranking: ' + Math.round(user.elo) + '
';
	},

	views: function (user) {
	    io.stdinNumber('db/views.csv', user, 'views');
	    var space = '      ';
	    return space + '- Views: ' + user.views;
	},

	money: function (user) {
	    io.stdinNumber('db/money.csv', user, 'money');
	    return 'Money: ' + '' + user.money;
	},

	tourWins: function (user) {
		io.stdinNumber('db/tourWins.csv', user, 'tourWins');
		return  ' | Tournament Wins: ' + user.tourWins + '
';
	},

	status: function (user) {
	    io.stdinString('db/status.csv', user, 'status');
	    if (user.status === '') {
	        user.status = 'This user hasn\'t set their status yet.';
	    }
	    return 'Status: "' + user.status + '"';
	},

	statusTime: function (user) {
	    io.stdinString('db/statusTime.csv', user, 'statusTime');
	    return ' ' + user.statusTime + '';
	}
};

var cmds = {
	profile: function (target, room, user, connection) {
	    if (!this.canBroadcast()) return;

	    var targetUser = this.targetUserOrSelf(target);

	    if (!targetUser) return this.sendReply('User ' + this.targetUsername + ' not found.');

	    var height = 75;

	    io.stdoutNumber('db/views.csv', targetUser, 'views', 1);

	     var display = Profile.avatar(targetUser, height) + Profile.name(targetUser) + Profile.views(targetUser) + '
' + Profile.rank(targetUser) + Profile.elo(targetUser) + Profile.money(targetUser) + Profile.tourWins(targetUser) + Profile.status(targetUser) + Profile.statusTime(targetUser);

	    if (!targetUser.authenticated) {
	        display = Profile.avatar(targetUser, height) + Profile.unregisteredName(targetUser) + Profile.views(targetUser) + '
' + Profile.rank(targetUser) + Profile.elo(targetUser) + Profile.money(targetUser) + Profile.tourWins(targetUser) + Profile.status(targetUser) + Profile.statusTime(targetUser);
	        return this.sendReplyBox(display);
	    } else if (typeof (targetUser.avatar) === typeof ('')) {
	        display = Profile.avatar(targetUser, height) + Profile.unregisteredName(targetUser) + Profile.views(targetUser) + '
' + Profile.rank(targetUser) + Profile.elo(targetUser) + Profile.money(targetUser) + Profile.tourWins(targetUser) + Profile.status(targetUser) + Profile.statusTime(targetUser);
	        return this.sendReplyBox(display);
	    } else {
	        return this.sendReplyBox(display);
	    }
	},

	setstatus: 'status',
	status: function(target, room, user){
		if (!target) return this.sendReply('|raw|Set your status for profile. Usage: /status status information');
		if (target.length > 30) return this.sendReply('Status is too long.');
		if (target.indexOf(',') >= 1) return this.sendReply('Unforunately, your status cannot contain a comma.');
		var escapeHTML = sanitize(target, true);
		io.stdoutString('db/status.csv', user, 'status', escapeHTML);

		var currentdate = new Date();
		var datetime = "Last Updated: " + (currentdate.getMonth()+1) + "/"+currentdate.getDate() + "/" + currentdate.getFullYear() + " @ "  + Utilities.formatAMPM(currentdate);
		io.stdoutString('db/statusTime.csv', user, 'statusTime', datetime);

		this.sendReply('Your status is now: "' + target + '"');
		if('+%@&~'.indexOf(user.group) >= 0) {
			room.add('|raw| * ' + user.name + ' set their status to: "' + escapeHTML + '"');
		}
	},
};

Object.merge(CommandParser.commands, cmds);
exports.cmds = cmds;
<|endoftext|>


<commit_before>import _ from 'lodash';
import settings from '../config/settings';
import ImmutableStore from '../lib/immutable-store';
import log from '../lib/log';
import request from 'superagent';

const migrate = () => { // schema change since v0.15.4
    // Clear localStorage
    localStorage.clear();

    // Remove "workspace" from ~/.cncrc
    request
        .del('/api/config')
        .query({ key: 'workspace' })
        .end((err, res) => {
        });
};

const defaultState = {
    workspace: {
        container: {
            default: {
                widgets: ['visualizer']
            },
            primary: {
                show: true,
                widgets: [
                    'connection', 'grbl', 'console', 'webcam'
                ]
            },
            secondary: {
                show: true,
                widgets: [
                    'axes', 'gcode', 'probe', 'spindle'
                ]
            }
        }
    },
    widgets: {
        axes: {
            jog: {
                selectedDistance: '1',
                customDistance: 10
            }
        },
        connection: {
            port: '',
            baudrate: 115200,
            autoReconnect: true
        },
        console: {
        },
        gcode: {
        },
        grbl: {
        },
        probe: {
            probeCommand: 'G38.2',
            probeDepth: 10,
            probeFeedrate: 20,
            tlo: 10,
            retractionDistance: 4
        },
        spindle: {
        },
        visualizer: {
        },
        webcam: {
            disabled: false,
            url: ''
        }
    }
};

let state;

try {
    let cnc = JSON.parse(localStorage.getItem('cnc')) || {};
    log.debug('cnc:', cnc);

    if (!(cnc.version)) {
        migrate();
    }

    state = _.merge({}, defaultState, cnc.state);

    { // Post-process the state after merging defaultState and cnc.state
        let defaultList = _.get(defaultState, 'workspace.container.default.widgets'); // use defaultState for the default container
        let primaryList = _.get(cnc.state, 'workspace.container.primary.widgets');
        let secondaryList = _.get(cnc.state, 'workspace.container.secondary.widgets');

        if (defaultList) {
            _.set(state, 'workspace.container.default.widgets', defaultList);
        }
        if (primaryList) {
            _.set(state, 'workspace.container.primary.widgets', primaryList);
        }
        if (secondaryList) {
            _.set(state, 'workspace.container.secondary.widgets', secondaryList);
        }
    }

    { // Remove duplicate ones
        let defaultList = _.get(state, 'workspace.container.default.widgets');
        let primaryList = _.get(state, 'workspace.container.primary.widgets');
        let secondaryList = _.get(state, 'workspace.container.secondary.widgets');

        primaryList = _(primaryList) // Keep the order of primaryList
            .uniq()
            .difference(defaultList) // exclude defaultList
            .value();

        secondaryList = _(secondaryList) // Keep the order of secondaryList
            .uniq()
            .difference(primaryList) // exclude primaryList
            .difference(defaultList) // exclude defaultList
            .value();

        _.set(state, 'workspace.container.primary.widgets', primaryList);
        _.set(state, 'workspace.container.secondary.widgets', secondaryList);
    }
}
catch(err) {
    state = _.merge({}, defaultState);
}

const store = new ImmutableStore(state);

store.on('change', (state) => {
    let cnc = {
        version: settings.version,
        state: state
    };
    localStorage.setItem('cnc', JSON.stringify(cnc));
});

export default store;
<commit_msg>Add shuttle settings<commit_after>import _ from 'lodash';
import settings from '../config/settings';
import ImmutableStore from '../lib/immutable-store';
import log from '../lib/log';
import request from 'superagent';

const migrate = () => { // schema change since v0.15.4
    // Clear localStorage
    localStorage.clear();

    // Remove "workspace" from ~/.cncrc
    request
        .del('/api/config')
        .query({ key: 'workspace' })
        .end((err, res) => {
        });
};

const defaultState = {
    workspace: {
        container: {
            default: {
                widgets: ['visualizer']
            },
            primary: {
                show: true,
                widgets: [
                    'connection', 'grbl', 'console', 'webcam'
                ]
            },
            secondary: {
                show: true,
                widgets: [
                    'axes', 'gcode', 'probe', 'spindle'
                ]
            }
        }
    },
    widgets: {
        axes: {
            jog: {
                selectedDistance: '1',
                customDistance: 10
            },
            shuttle: {
                feedrateMin: 300,
                feedrateMax: 1500,
                hertz: 10,
                overshoot: 1
            }
        },
        connection: {
            port: '',
            baudrate: 115200,
            autoReconnect: true
        },
        console: {
        },
        gcode: {
        },
        grbl: {
        },
        probe: {
            probeCommand: 'G38.2',
            probeDepth: 10,
            probeFeedrate: 20,
            tlo: 10,
            retractionDistance: 4
        },
        spindle: {
        },
        visualizer: {
        },
        webcam: {
            disabled: false,
            url: ''
        }
    }
};

let state;

try {
    let cnc = JSON.parse(localStorage.getItem('cnc')) || {};
    log.debug('cnc:', cnc);

    if (!(cnc.version)) {
        migrate();
    }

    state = _.merge({}, defaultState, cnc.state);

    { // Post-process the state after merging defaultState and cnc.state
        let defaultList = _.get(defaultState, 'workspace.container.default.widgets'); // use defaultState for the default container
        let primaryList = _.get(cnc.state, 'workspace.container.primary.widgets');
        let secondaryList = _.get(cnc.state, 'workspace.container.secondary.widgets');

        if (defaultList) {
            _.set(state, 'workspace.container.default.widgets', defaultList);
        }
        if (primaryList) {
            _.set(state, 'workspace.container.primary.widgets', primaryList);
        }
        if (secondaryList) {
            _.set(state, 'workspace.container.secondary.widgets', secondaryList);
        }
    }

    { // Remove duplicate ones
        let defaultList = _.get(state, 'workspace.container.default.widgets');
        let primaryList = _.get(state, 'workspace.container.primary.widgets');
        let secondaryList = _.get(state, 'workspace.container.secondary.widgets');

        primaryList = _(primaryList) // Keep the order of primaryList
            .uniq()
            .difference(defaultList) // exclude defaultList
            .value();

        secondaryList = _(secondaryList) // Keep the order of secondaryList
            .uniq()
            .difference(primaryList) // exclude primaryList
            .difference(defaultList) // exclude defaultList
            .value();

        _.set(state, 'workspace.container.primary.widgets', primaryList);
        _.set(state, 'workspace.container.secondary.widgets', secondaryList);
    }
}
catch(err) {
    state = _.merge({}, defaultState);
}

const store = new ImmutableStore(state);

store.on('change', (state) => {
    let cnc = {
        version: settings.version,
        state: state
    };
    localStorage.setItem('cnc', JSON.stringify(cnc));
});

export default store;
<|endoftext|>


<commit_before>/**
 * Room I/O is a socket wrapper which implements the basic functions of io part
 * @type {*|exports|module.exports}
 */
var express = require ('express');
var io = require ('socket.io') ();
var rooms = require ('./models/rooms');
var app = require ('../app');
var auth = require ('./auth');
var socketRouter = require('./socketRouter');

var lobby = rooms.getLobby ();
var hashOfUserObjects = {};

var listen = function (server) {
	io.listen (server);
	console.log (app.locals);
	console.log ('Server Started and Socket listened on ' + app.get ('server-port'));
}

/**
 * Middleware to authenticate the incoming socket connection
 * @param socket
 * @param next
 */
var authenticateSocketConnection = function(socket, next) {
	// Retrieve handshake data from socket
	var handshakeData = socket.request;
	// Then extract client's JWT token
	var jwtToken = handshakeData._query.token;

	// Verify the JWT token
	auth.verify(jwtToken, function(err, decoded){
		if (err){
			// Authentication failed, we throw an error
			console.log(err);
			next(new Error('Not Authorized!'));
		} else {
			// Extract Client's Id and Name and append them to the socket object
			socket.id = decoded.id;
			socket.name = decoded.name;
			next ();
		}
	})
}

// We assign the above middleware
var roomio = io.of('/room').use(authenticateSocketConnection);

roomio.on ('connection', function (socket) {
	// Now at this point, incoming client's connection has been authenticated
	var clientId = socket.id;
	var clientName = socket.name;

	console.log ('User: ' + clientName + ' has connected');
	console.log (socket.request.headers);

	var socketClient = new rooms.SocketClient (clientId, socket);

	socketClient.joinRoom ('testid');
	socketClient.groupBroadcast ('message', {});

	//console.log(socketClient.getCurrentGroup().presentation.getAllSlidesAsJSON());
	//console.log(socketClient.getCurrentGroup().presentation.currentSlide);
	//console.log(socketClient.getCurrentGroup().presentation.nextSlide());
	//console.log(socketClient.getCurrentGroup().presentation.currentSlide);

	socketRouter(clientId, clientName, socketClient, lobby);

	/**
	 * Message IO Handler
	 * */

	socketClient.on ('msgToGroup', function(msg){console.log(socketClient); socketClient.groupBroadcast ('msgToGroup', {clientName: clientName, msg: msg.msg });});

	socketClient.on ('msgToRoom', function(msg){console.log(socketClient); socketClient.roomBroadcast ('msgToRoom', {clientName: clientName, msg: msg.msg });});

	socketClient.on ('msgToUser', function(msg){console.log(socketClient); socketClient.personalMessage ('msgToUser', {clientName: clientName, msg: msg.msg, receiverId: msg.receiverId})});

	/**
	 * Group IO Handler
	 * */
	socketClient.on('getMap', function(){
		socketClient.emit('sendMap', {roomMap: socketClient.getRoom()});
	})

	/**
	 * Canvas IO Handler
	 * */
	roomio.emit ('canvasState', getAllCanvasObjects ());

	socketClient.on ('canvasAction', canvasAction);

	socketClient.on ('canvasUndo', canvasUndo);

	socketClient.on ('canvasClear', canvasClear);

	// emit slides filepath to client
	socketClient.emit("slidesPaths", socketClient.getCurrentGroup().presentation.getAllSlidesAsJSON());

	// emit current slide
	socketClient.emit("currentSlide", socketClient.getCurrentGroup().presentation.currentSlide);

	socketClient.on('nextSlide', function() {
		socketClient.getCurrentGroup().presentation.nextSlide();
		socketClient.emit("currentSlide", socketClient.getCurrentGroup().presentation.currentSlide);
	});

	socketClient.on('prevSlide', function() {
		socketClient.getCurrentGroup().presentation.previousSlide();
		socketClient.emit("currentSlide", socketClient.getCurrentGroup().presentation.currentSlide);
	});

	/*
	 * WebRTC IO Handler
	 * */
	socketClient.on ('Emit Message', onSetupMessage (socketClient));

	/*
	 * User Status Handler
	 * */
	socketClient.on ('New User', onNewUser (socketClient, socketClient.socketID));

	socketClient.on ('disconnect', onDisconnection (socketClient));

	socketClient.on ('joinRoom', joinRoom (clientId));

	socketClient.on ('leaveRoom', leaveRoom (clientId));
	// -------- End of Web RTC IO -----------//
});

/**
 * ================ User Status IO =================
 * =================================================
 * */
function joinRoom (clientId) {
	return function (msg) {
		var roomId = msg.roomId;
		lobby.getUser (clientId).joinRoom (roomId);
		lobby.getUser (clientId).roomBroadcast ('joinRoom', clientId);
	}
}

function leaveRoom (clientId) {
	return function () {
		lobby.getUser (clientId).leaveRoom ();
		lobby.getUser (clientId).roomBroadcast ('leaveRoom', clientId);
	}
}

function onNewUser (socketClient, clientId) {
	return function (message) {
		console.log ('===================================== Got New User:', message);	        // for a real app, would be room only (not broadcast)

		addNewUserToList (clientId);
		responseIDToClient (socketClient, clientId);
		responseExistingUserToClient (socketClient);
		broadCastID (socketClient, clientId);
	}
}

function broadCastID (socketClient, ID) {
	socketClient.roomBroadcast ('New Joined', {'userID': ID});
}

function onDisconnection (socketClient) {
	return function () {
		console.log ('Disconnection: ', socketClient.userID);

		// Set disconnect value
		socketClient.setDisconnect ();

		// Notify client side WebRTC on user leave
		socketClient.notifyGroupUsersOnUserLeave (socketClient.userID);
	}
}

/**
 * ================== WebRTC IO ===================
 * =================================================
 * */
var userIDList = [];
function addNewUserToList (curID) {
	userIDList.push (curID);
}

function responseIDToClient (socketClient, ID) {
	socketClient.emit ('Assigned ID', {'assignedID': ID});
}

// Repond with all existing connected user in current group except myself
function responseExistingUserToClient (socketClient) {
	var currentGroupUserList = socketClient.getCurrentGroupUserList ();
	var groupUserIDList = [];
	for (var index in currentGroupUserList) {
		if (currentGroupUserList[index].socketID != socketClient.socketID) {
			groupUserIDList.push (currentGroupUserList[index].socketID);
		}
	}
	socketClient.emit ('Existing UserList', {'userIDList': groupUserIDList});
}

function onSetupMessage (socketClient) {
	return function (message) {
		console.log ('!!!!!!! Set Up MESSAGE');
		socketClient.roomBroadcast ('Setup Message', message);
	}
}

/**
 * =================== Canvas IO ===================
 * =================================================
 * */
var canvasAction = function (action) {
	var clientId = socket.id;
	console.log (clientId);
	hashOfUserObjects[clientId].push (action);

	roomio.emit ('canvasState', getAllCanvasObjects ());

	// console.log(redisClient.lpush('canvasAction', action));

	// canvasio.emit('canvasAction', action);
	console.log (hashOfUserObjects);
};

var canvasUndo = function () {
	var clientId = socket.id;
	hashOfUserObjects[clientId].pop ();
	roomio.emit ('canvasState', getAllCanvasObjects ());
};

var canvasClear = function () {
	clearAllCanvasObjects ();
	roomio.emit ('canvasState', getAllCanvasObjects ());
};

var getAllCanvasObjects = function () {
	var currentCavansObjects = [];
	for (var userObjectsKey in hashOfUserObjects) {
		currentCavansObjects = currentCavansObjects.concat (hashOfUserObjects[userObjectsKey]);
		// console.log(hashOfUserObjects[userObjectsKey]);
	}
	return currentCavansObjects;
};

var clearAllCanvasObjects = function () {
	for (var userObjectsKey in hashOfUserObjects) {
		hashOfUserObjects[userObjectsKey] = [];
	}
};

module.exports.listen = listen;<commit_msg>fixed slide broadcast<commit_after>/**
 * Room I/O is a socket wrapper which implements the basic functions of io part
 * @type {*|exports|module.exports}
 */
var express = require ('express');
var io = require ('socket.io') ();
var rooms = require ('./models/rooms');
var app = require ('../app');
var auth = require ('./auth');
var socketRouter = require('./socketRouter');

var lobby = rooms.getLobby ();
var hashOfUserObjects = {};

var listen = function (server) {
	io.listen (server);
	console.log (app.locals);
	console.log ('Server Started and Socket listened on ' + app.get ('server-port'));
}

/**
 * Middleware to authenticate the incoming socket connection
 * @param socket
 * @param next
 */
var authenticateSocketConnection = function(socket, next) {
	// Retrieve handshake data from socket
	var handshakeData = socket.request;
	// Then extract client's JWT token
	var jwtToken = handshakeData._query.token;

	// Verify the JWT token
	auth.verify(jwtToken, function(err, decoded){
		if (err){
			// Authentication failed, we throw an error
			console.log(err);
			next(new Error('Not Authorized!'));
		} else {
			// Extract Client's Id and Name and append them to the socket object
			socket.id = decoded.id;
			socket.name = decoded.name;
			next ();
		}
	})
}

// We assign the above middleware
var roomio = io.of('/room').use(authenticateSocketConnection);

roomio.on ('connection', function (socket) {
	// Now at this point, incoming client's connection has been authenticated
	var clientId = socket.id;
	var clientName = socket.name;

	console.log ('User: ' + clientName + ' has connected');
	console.log (socket.request.headers);

	var socketClient = new rooms.SocketClient (clientId, socket);

	socketClient.joinRoom ('testid');
	socketClient.groupBroadcast ('message', {});

	//console.log(socketClient.getCurrentGroup().presentation.getAllSlidesAsJSON());
	//console.log(socketClient.getCurrentGroup().presentation.currentSlide);
	//console.log(socketClient.getCurrentGroup().presentation.nextSlide());
	//console.log(socketClient.getCurrentGroup().presentation.currentSlide);

	socketRouter(clientId, clientName, socketClient, lobby);

	/**
	 * Message IO Handler
	 * */

	socketClient.on ('msgToGroup', function(msg){console.log(socketClient); socketClient.groupBroadcast ('msgToGroup', {clientName: clientName, msg: msg.msg });});

	socketClient.on ('msgToRoom', function(msg){console.log(socketClient); socketClient.roomBroadcast ('msgToRoom', {clientName: clientName, msg: msg.msg });});

	socketClient.on ('msgToUser', function(msg){console.log(socketClient); socketClient.personalMessage ('msgToUser', {clientName: clientName, msg: msg.msg, receiverId: msg.receiverId})});

	/**
	 * Group IO Handler
	 * */
	socketClient.on('getMap', function(){
		socketClient.emit('sendMap', {roomMap: socketClient.getRoom()});
	})

	/**
	 * Canvas IO Handler
	 * */
	roomio.emit ('canvasState', getAllCanvasObjects ());

	socketClient.on ('canvasAction', canvasAction);

	socketClient.on ('canvasUndo', canvasUndo);

	socketClient.on ('canvasClear', canvasClear);

	// emit slides filepath to client
	socketClient.emit("slidesPaths", socketClient.getCurrentGroup().presentation.getAllSlidesAsJSON());

	// emit current slide
	socketClient.emit("currentSlide", socketClient.getCurrentGroup().presentation.currentSlide);

	socketClient.on('nextSlide', function() {
		socketClient.getCurrentGroup().presentation.nextSlide();
		socketClient.groupBroadcast("currentSlide", socketClient.getCurrentGroup().presentation.currentSlide);
	});

	socketClient.on('prevSlide', function() {
		socketClient.getCurrentGroup().presentation.previousSlide();
		socketClient.groupBroadcast("currentSlide", socketClient.getCurrentGroup().presentation.currentSlide);
	});

	/*
	 * WebRTC IO Handler
	 * */
	socketClient.on ('Emit Message', onSetupMessage (socketClient));

	/*
	 * User Status Handler
	 * */
	socketClient.on ('New User', onNewUser (socketClient, socketClient.socketID));

	socketClient.on ('disconnect', onDisconnection (socketClient));

	socketClient.on ('joinRoom', joinRoom (clientId));

	socketClient.on ('leaveRoom', leaveRoom (clientId));
	// -------- End of Web RTC IO -----------//
});

/**
 * ================ User Status IO =================
 * =================================================
 * */
function joinRoom (clientId) {
	return function (msg) {
		var roomId = msg.roomId;
		lobby.getUser (clientId).joinRoom (roomId);
		lobby.getUser (clientId).roomBroadcast ('joinRoom', clientId);
	}
}

function leaveRoom (clientId) {
	return function () {
		lobby.getUser (clientId).leaveRoom ();
		lobby.getUser (clientId).roomBroadcast ('leaveRoom', clientId);
	}
}

function onNewUser (socketClient, clientId) {
	return function (message) {
		console.log ('===================================== Got New User:', message);	        // for a real app, would be room only (not broadcast)

		addNewUserToList (clientId);
		responseIDToClient (socketClient, clientId);
		responseExistingUserToClient (socketClient);
		broadCastID (socketClient, clientId);
	}
}

function broadCastID (socketClient, ID) {
	socketClient.roomBroadcast ('New Joined', {'userID': ID});
}

function onDisconnection (socketClient) {
	return function () {
		console.log ('Disconnection: ', socketClient.userID);

		// Set disconnect value
		socketClient.setDisconnect ();

		// Notify client side WebRTC on user leave
		socketClient.notifyGroupUsersOnUserLeave (socketClient.userID);
	}
}

/**
 * ================== WebRTC IO ===================
 * =================================================
 * */
var userIDList = [];
function addNewUserToList (curID) {
	userIDList.push (curID);
}

function responseIDToClient (socketClient, ID) {
	socketClient.emit ('Assigned ID', {'assignedID': ID});
}

// Repond with all existing connected user in current group except myself
function responseExistingUserToClient (socketClient) {
	var currentGroupUserList = socketClient.getCurrentGroupUserList ();
	var groupUserIDList = [];
	for (var index in currentGroupUserList) {
		if (currentGroupUserList[index].socketID != socketClient.socketID) {
			groupUserIDList.push (currentGroupUserList[index].socketID);
		}
	}
	socketClient.emit ('Existing UserList', {'userIDList': groupUserIDList});
}

function onSetupMessage (socketClient) {
	return function (message) {
		console.log ('!!!!!!! Set Up MESSAGE');
		socketClient.roomBroadcast ('Setup Message', message);
	}
}

/**
 * =================== Canvas IO ===================
 * =================================================
 * */
var canvasAction = function (action) {
	var clientId = socket.id;
	console.log (clientId);
	hashOfUserObjects[clientId].push (action);

	roomio.emit ('canvasState', getAllCanvasObjects ());

	// console.log(redisClient.lpush('canvasAction', action));

	// canvasio.emit('canvasAction', action);
	console.log (hashOfUserObjects);
};

var canvasUndo = function () {
	var clientId = socket.id;
	hashOfUserObjects[clientId].pop ();
	roomio.emit ('canvasState', getAllCanvasObjects ());
};

var canvasClear = function () {
	clearAllCanvasObjects ();
	roomio.emit ('canvasState', getAllCanvasObjects ());
};

var getAllCanvasObjects = function () {
	var currentCavansObjects = [];
	for (var userObjectsKey in hashOfUserObjects) {
		currentCavansObjects = currentCavansObjects.concat (hashOfUserObjects[userObjectsKey]);
		// console.log(hashOfUserObjects[userObjectsKey]);
	}
	return currentCavansObjects;
};

var clearAllCanvasObjects = function () {
	for (var userObjectsKey in hashOfUserObjects) {
		hashOfUserObjects[userObjectsKey] = [];
	}
};

module.exports.listen = listen;<|endoftext|>


<commit_before>/**
 * This module defines the p5.Shader class
 * @module Lights, Camera
 * @submodule Shaders
 * @for p5
 * @requires core
 */

var p5 = require('../core/core');

/**
 * Shader class for WEBGL Mode
 * @class p5.Shader
 * @constructor
 * @param {p5.RendererGL} renderer an instance of p5.RendererGL that
 * will provide the GL context for this new p5.Shader
 * @param {String} vertSrc source code for the vertex shader (as a string)
 * @param {String} fragSrc source code for the fragment shader (as a string)
 */
p5.Shader = function(renderer, vertSrc, fragSrc) {
  // TODO: adapt this to not take ids, but rather,
  // to take the source for a vertex and fragment shader
  // to enable custom shaders at some later date
  this._renderer = renderer;
  this._vertSrc = vertSrc;
  this._fragSrc = fragSrc;
  this._vertShader = -1;
  this._fragShader = -1;
  this._glProgram = 0;
  this._loadedAttributes = false;
  this.attributes = {};
  this._loadedUniforms = false;
  this.uniforms = {};
  this._bound = false;
  this.samplers = [];

  return this;
};

/**
 * Creates, compiles, and links the shader based on its
 * sources for the vertex and fragment shaders (provided
 * to the constructor). Populates known attributes and
 * uniforms from the shader.
 * @method init
 * @chainable
 * @private
 */
p5.Shader.prototype.init = function() {
  if (this._glProgram === 0 /* or context is stale? */) {
    var gl = this._renderer.GL;

    // @todo: once custom shading is allowed,
    // friendly error messages should be used here to share
    // compiler and linker errors.

    //set up the shader by
    // 1. creating and getting a gl id for the shader program,
    // 2. compliling its vertex & fragment sources,
    // 3. linking the vertex and fragment shaders
    this._vertShader = gl.createShader(gl.VERTEX_SHADER);
    //load in our default vertex shader
    gl.shaderSource(this._vertShader, this._vertSrc);
    gl.compileShader(this._vertShader);
    // if our vertex shader failed compilation?
    if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) {
      console.error('Yikes! An error occurred compiling the vertex shader:' +
        gl.getShaderInfoLog(this._vertShader));
      return null;
    }

    this._fragShader = gl.createShader(gl.FRAGMENT_SHADER);
    //load in our material frag shader
    gl.shaderSource(this._fragShader, this._fragSrc);
    gl.compileShader(this._fragShader);
    // if our frag shader failed compilation?
    if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) {
      console.error('Darn! An error occurred compiling the fragment shader:' +
        gl.getShaderInfoLog(this._fragShader));
      return null;
    }

    this._glProgram = gl.createProgram();
    gl.attachShader(this._glProgram, this._vertShader);
    gl.attachShader(this._glProgram, this._fragShader);
    gl.linkProgram(this._glProgram);
    if (!gl.getProgramParameter(this._glProgram, gl.LINK_STATUS)) {
      console.error('Snap! Error linking shader program: ' +
        gl.getProgramInfoLog(this._glProgram));
    }

    this._loadAttributes();
    this._loadUniforms();
  }
  return this;
};

/**
 * Queries the active attributes for this shader and loads
 * their names and locations into the attributes array.
 * @method _loadAttributes
 * @private
 */
p5.Shader.prototype._loadAttributes = function() {
  if (this._loadedAttributes) {
    return;
  }

  this.attributes = {};

  var gl = this._renderer.GL;

  var numAttributes = gl.getProgramParameter(this._glProgram, gl.ACTIVE_ATTRIBUTES);
  for(var i = 0; i < numAttributes; ++i){
    var attributeInfo = gl.getActiveAttrib(this._glProgram, i);
    var name = attributeInfo.name;
    var location = gl.getAttribLocation(this._glProgram, name);
    var attribute = {};
    attribute.name = name;
    attribute.location = location;
    attribute.type = attributeInfo.type;
    attribute.size = attributeInfo.size;
    this.attributes[name] = attribute;
  }

  this._loadedAttributes = true;
};

/**
 * Queries the active uniforms for this shader and loads
 * their names and locations into the uniforms array.
 * @method _loadUniforms
 * @private
 */
p5.Shader.prototype._loadUniforms = function() {
  if (this._loadedUniforms) {
    return;
  }

  var gl = this._renderer.GL;

  // Inspect shader and cache uniform info
  var numUniforms = gl.getProgramParameter(this._glProgram, gl.ACTIVE_UNIFORMS);

  var samplerIndex = 0;
  for(var i = 0; i < numUniforms; ++i){
    var uniformInfo = gl.getActiveUniform(this._glProgram, i);
    var uniform = {};
    uniform.location = gl.getUniformLocation(this._glProgram, uniformInfo.name);
    uniform.size = uniformInfo.size;
    var uniformName = uniformInfo.name;
    //uniforms thats are arrays have their name returned as
    //someUniform[0] which is a bit silly so we trim it
    //off here. The size property tells us that its an array
    //so we dont lose any information by doing this
    if(uniformInfo.size > 1) {
      uniformName = uniformName.substring(0, uniformName.indexOf('[0]'));
    }
    uniform.name = uniformName;
    uniform.type = uniformInfo.type;
    if(uniform.type === gl.SAMPLER_2D) {
      uniform.samplerIndex = samplerIndex;
      samplerIndex++;
      this.samplers.push(uniform);
    }
    this.uniforms[uniformName] = uniform;
  }
  this._loadedUniforms = true;
};

p5.Shader.prototype.compile = function() {
  // TODO
};

/**
 * initializes (if needed) and binds the shader program.
 * @method bindShader
 * @private
 */
p5.Shader.prototype.bindShader = function () {
  this.init();
  if (!this._bound) {
    this.useProgram();
    this._bound = true;
    this.bindTextures();

    this._loadAttributes();
    this._loadUniforms();

    this._renderer._setDefaultCamera();
    this._setMatrixUniforms();
    if(this === this._renderer.curStrokeShader) {
      this._setViewportUniform();
    }
  }
};

/**
 * @method unbindShader
 * @chainable
 * @private
 */
p5.Shader.prototype.unbindShader = function () {
  if (this._bound) {
    this.unbindTextures();
    //this._renderer.GL.useProgram(0); ??
    this._bound = false;
  }
  return this;
};

p5.Shader.prototype.bindTextures = function () {
  var gl = this._renderer.GL;
  for (var i = 0;  i < this.samplers.length; i++) {
    var uniform = this.samplers[i];
    var tex = uniform.texture;
    if (tex === undefined) {
      // user hasn't yet supplied a texture for this slot.
      // (or there may not be one--maybe just lighting),
      // so we supply a default texture instead.
      tex = this._renderer._getEmptyTexture();
    }
    gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
    tex.bindTexture();
    tex.update();
    gl.uniform1i(uniform.location, uniform.samplerIndex);
  }
};

p5.Shader.prototype.unbindTextures = function () {
  // TODO: migrate stuff from material.js here
  // - OR - have material.js define this function
};

p5.Shader.prototype._setMatrixUniforms = function() {
  this.setUniform('uProjectionMatrix', this._renderer.uPMatrix.mat4);
  this.setUniform('uModelViewMatrix', this._renderer.uMVMatrix.mat4);
  if(this === this._renderer.curFillShader) {
    this._renderer.uNMatrix.inverseTranspose(this._renderer.uMVMatrix);
    this.setUniform('uNormalMatrix', this._renderer.uNMatrix.mat3);
  }
};

p5.Shader.prototype._setViewportUniform = function() {
  this.setUniform('uViewport', this._renderer.GL.getParameter(this._renderer.GL.VIEWPORT));
};

/**
 * @method useProgram
 * @chainable
 * @private
 */
p5.Shader.prototype.useProgram = function () {
  var gl = this._renderer.GL;
  gl.useProgram(this._glProgram);
  return this;
};

/**
 * Wrapper around gl.uniform functions.
 * As we store uniform info in the shader we can use that
 * to do type checking on the supplied data and call
 * the appropriate function.
 * @method setUniform
 * @chainable
 * @param {String} uniformName the name of the uniform in the
 * shader program
 * @param {Object} data the data to be associated with that uniform; type
 * varies (could be a single numerical value, array, matrix, or
 * texture / sampler reference)
 */
p5.Shader.prototype.setUniform = function(uniformName, data)
{
  //@todo update all current gl.uniformXX calls

  var gl = this._renderer.GL;
  // todo: is this safe to do here?
  // todo: store the values another way?
  this.useProgram();

  // TODO BIND?
  var uniform = this.uniforms[uniformName];
  if(!uniform) {
    //@todo warning?
    return;
  }
  var location = uniform.location;

  switch(uniform.type){
    case gl.BOOL:
      if(data === true) {
        gl.uniform1i(location, 1);
      }
      else {
        gl.uniform1i(location, 0);
      }
      break;
    case gl.INT:
      gl.uniform1i(location, data);
      break;
    case gl.FLOAT:
      if(uniform.size > 1){
        gl.uniform1fv(location, data);
      }
      else{
        gl.uniform1f(location, data);
      }
      break;
    case gl.FLOAT_MAT3:
      gl.uniformMatrix3fv(location, false, data);
      break;
    case gl.FLOAT_MAT4:
      gl.uniformMatrix4fv(location, false, data);
      break;
    case gl.FLOAT_VEC2:
      if(uniform.size > 1){
        gl.uniform2fv(location, data);
      }
      else{
        gl.uniform2f(location, data[0], data[1]);
      }
      break;
    case gl.FLOAT_VEC3:
      if(uniform.size > 1){
        gl.uniform3fv(location, data);
      }
      else{
        gl.uniform3f(location, data[0], data[1], data[2]);
      }
      break;
    case gl.FLOAT_VEC4:
      if(uniform.size > 1){
        gl.uniform4fv(location, data);
      }
      else{
        gl.uniform4f(location, data[0], data[1], data[2], data[3]);
      }
      break;
    case gl.SAMPLER_2D:
      gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
      uniform.texture = this._renderer.getTexture(data);
      gl.uniform1i(uniform.location, uniform.samplerIndex);
      break;
    //@todo complete all types
  }
  return this;
};

/* NONE OF THIS IS FAST OR EFFICIENT BUT BEAR WITH ME
 *
 * these shader "type" query methods are used by various
 * facilities of the renderer to determine if changing
 * the shader type for the required action (for example,
 * do we need to load the default lighting shader if the
 * current shader cannot handle lighting?)
 *
 **/

p5.Shader.prototype.isLightShader = function () {
  return this.uniforms.uUseLighting !== undefined ||
    this.uniforms.uAmbientLightCount !== undefined ||
    this.uniforms.uDirectionalLightCount !== undefined ||
    this.uniforms.uPointLightCount !== undefined ||
    this.uniforms.uAmbientColor !== undefined ||
    this.uniforms.uDirectionalColor !== undefined ||
    this.uniforms.uPointLightLocation !== undefined ||
    this.uniforms.uPointLightColor !== undefined ||
    this.uniforms.uLightingDirection !== undefined ||
    this.uniforms.uSpecular !== undefined;
};

p5.Shader.prototype.isTextureShader = function () {
  return this.samplerIndex > 0;
};

p5.Shader.prototype.isColorShader = function () {
  return this.attributes.aVertexColor !== undefined ||
    this.uniforms.uMaterialColor !== undefined;
};

p5.Shader.prototype.isTexLightShader = function () {
  return this.isLightShader() && this.isTextureShader();
};

p5.Shader.prototype.isStrokeShader = function () {
  return this.uniforms.uStrokeWeight !== undefined;
};

/**
 * @method enableAttrib
 * @chainable
 * @private
 */
p5.Shader.prototype.enableAttrib = function(loc, size,
  type, normalized, stride, offset) {
  var gl = this._renderer.GL;
  if(loc !== -1) {
    gl.enableVertexAttribArray(loc);
    gl.vertexAttribPointer(loc, size, type, normalized, stride, offset);
  }
  return this;
};

module.exports = p5.Shader;
<commit_msg>add example for p5.Shader constructor<commit_after>/**
 * This module defines the p5.Shader class
 * @module Lights, Camera
 * @submodule Shaders
 * @for p5
 * @requires core
 */

var p5 = require('../core/core');

/**
 * Shader class for WEBGL Mode
 * @class p5.Shader
 * @constructor
 * @param {p5.RendererGL} renderer an instance of p5.RendererGL that
 * will provide the GL context for this new p5.Shader
 * @param {String} vertSrc source code for the vertex shader (as a string)
 * @param {String} fragSrc source code for the fragment shader (as a string)
 * @example
 *

 *
 * var varying = 'precision highp float; varying vec2 vPos;';
 * var vs = varying
 * +'attribute vec3 aPosition;'
 * +'void main() { vPos = (gl_Position = vec4(aPosition,1.0)).xy; }';
 * var fs = varying
 * +'uniform vec2 p;'
 * +'uniform float r;'
 * +'const int I = 500;'
 * +'void main() {'
 * +'vec2 c = p + vPos * r, z = c;'
 * +'float n = 0.0;'
 * +'for (int i = I; i > 0; i --) {'
 * +'	 if(z.x*z.x+z.y*z.y > 4.0) {'
 * +'    n = float(i)/float(I);'
 * +'    break;'
 * +'  }'
 * +'	 z = vec2(z.x*z.x-z.y*z.y, 2.0*z.x*z.y) + c;'
 * +'}'
 * +'gl_FragColor = vec4(0.5-cos(n*17.0)/2.0,0.5-cos(n*13.0)/2.0,0.5-cos(n*23.0)/2.0,1.0);'
 * +'}';
 *
 * var mandel;
 * function setup() {
 *   var renderer = createCanvas(100, 100, WEBGL);
 *   mandel = new p5.Shader(renderer, vs, fs);
 *   shader(mandel);
 *   mandel.setUniform('p', [-0.74364388703,0.13182590421]);
 *   noStroke();
 * }
 *
 * function draw() {
 *  mandel.setUniform('r', 1.5 * exp(-6.5 * (1 + sin(millis()/2000))));
 *  quad(-1, -1, 1, -1, 1, 1, -1, 1);
 * }
 *
 *

 */
p5.Shader = function(renderer, vertSrc, fragSrc) {
  // TODO: adapt this to not take ids, but rather,
  // to take the source for a vertex and fragment shader
  // to enable custom shaders at some later date
  this._renderer = renderer;
  this._vertSrc = vertSrc;
  this._fragSrc = fragSrc;
  this._vertShader = -1;
  this._fragShader = -1;
  this._glProgram = 0;
  this._loadedAttributes = false;
  this.attributes = {};
  this._loadedUniforms = false;
  this.uniforms = {};
  this._bound = false;
  this.samplers = [];

  return this;
};

/**
 * Creates, compiles, and links the shader based on its
 * sources for the vertex and fragment shaders (provided
 * to the constructor). Populates known attributes and
 * uniforms from the shader.
 * @method init
 * @chainable
 * @private
 */
p5.Shader.prototype.init = function() {
  if (this._glProgram === 0 /* or context is stale? */) {
    var gl = this._renderer.GL;

    // @todo: once custom shading is allowed,
    // friendly error messages should be used here to share
    // compiler and linker errors.

    //set up the shader by
    // 1. creating and getting a gl id for the shader program,
    // 2. compliling its vertex & fragment sources,
    // 3. linking the vertex and fragment shaders
    this._vertShader = gl.createShader(gl.VERTEX_SHADER);
    //load in our default vertex shader
    gl.shaderSource(this._vertShader, this._vertSrc);
    gl.compileShader(this._vertShader);
    // if our vertex shader failed compilation?
    if (!gl.getShaderParameter(this._vertShader, gl.COMPILE_STATUS)) {
      console.error('Yikes! An error occurred compiling the vertex shader:' +
        gl.getShaderInfoLog(this._vertShader));
      return null;
    }

    this._fragShader = gl.createShader(gl.FRAGMENT_SHADER);
    //load in our material frag shader
    gl.shaderSource(this._fragShader, this._fragSrc);
    gl.compileShader(this._fragShader);
    // if our frag shader failed compilation?
    if (!gl.getShaderParameter(this._fragShader, gl.COMPILE_STATUS)) {
      console.error('Darn! An error occurred compiling the fragment shader:' +
        gl.getShaderInfoLog(this._fragShader));
      return null;
    }

    this._glProgram = gl.createProgram();
    gl.attachShader(this._glProgram, this._vertShader);
    gl.attachShader(this._glProgram, this._fragShader);
    gl.linkProgram(this._glProgram);
    if (!gl.getProgramParameter(this._glProgram, gl.LINK_STATUS)) {
      console.error('Snap! Error linking shader program: ' +
        gl.getProgramInfoLog(this._glProgram));
    }

    this._loadAttributes();
    this._loadUniforms();
  }
  return this;
};

/**
 * Queries the active attributes for this shader and loads
 * their names and locations into the attributes array.
 * @method _loadAttributes
 * @private
 */
p5.Shader.prototype._loadAttributes = function() {
  if (this._loadedAttributes) {
    return;
  }

  this.attributes = {};

  var gl = this._renderer.GL;

  var numAttributes = gl.getProgramParameter(this._glProgram, gl.ACTIVE_ATTRIBUTES);
  for(var i = 0; i < numAttributes; ++i){
    var attributeInfo = gl.getActiveAttrib(this._glProgram, i);
    var name = attributeInfo.name;
    var location = gl.getAttribLocation(this._glProgram, name);
    var attribute = {};
    attribute.name = name;
    attribute.location = location;
    attribute.type = attributeInfo.type;
    attribute.size = attributeInfo.size;
    this.attributes[name] = attribute;
  }

  this._loadedAttributes = true;
};

/**
 * Queries the active uniforms for this shader and loads
 * their names and locations into the uniforms array.
 * @method _loadUniforms
 * @private
 */
p5.Shader.prototype._loadUniforms = function() {
  if (this._loadedUniforms) {
    return;
  }

  var gl = this._renderer.GL;

  // Inspect shader and cache uniform info
  var numUniforms = gl.getProgramParameter(this._glProgram, gl.ACTIVE_UNIFORMS);

  var samplerIndex = 0;
  for(var i = 0; i < numUniforms; ++i){
    var uniformInfo = gl.getActiveUniform(this._glProgram, i);
    var uniform = {};
    uniform.location = gl.getUniformLocation(this._glProgram, uniformInfo.name);
    uniform.size = uniformInfo.size;
    var uniformName = uniformInfo.name;
    //uniforms thats are arrays have their name returned as
    //someUniform[0] which is a bit silly so we trim it
    //off here. The size property tells us that its an array
    //so we dont lose any information by doing this
    if(uniformInfo.size > 1) {
      uniformName = uniformName.substring(0, uniformName.indexOf('[0]'));
    }
    uniform.name = uniformName;
    uniform.type = uniformInfo.type;
    if(uniform.type === gl.SAMPLER_2D) {
      uniform.samplerIndex = samplerIndex;
      samplerIndex++;
      this.samplers.push(uniform);
    }
    this.uniforms[uniformName] = uniform;
  }
  this._loadedUniforms = true;
};

p5.Shader.prototype.compile = function() {
  // TODO
};

/**
 * initializes (if needed) and binds the shader program.
 * @method bindShader
 * @private
 */
p5.Shader.prototype.bindShader = function () {
  this.init();
  if (!this._bound) {
    this.useProgram();
    this._bound = true;
    this.bindTextures();

    this._loadAttributes();
    this._loadUniforms();

    this._renderer._setDefaultCamera();
    this._setMatrixUniforms();
    if(this === this._renderer.curStrokeShader) {
      this._setViewportUniform();
    }
  }
};

/**
 * @method unbindShader
 * @chainable
 * @private
 */
p5.Shader.prototype.unbindShader = function () {
  if (this._bound) {
    this.unbindTextures();
    //this._renderer.GL.useProgram(0); ??
    this._bound = false;
  }
  return this;
};

p5.Shader.prototype.bindTextures = function () {
  var gl = this._renderer.GL;
  for (var i = 0;  i < this.samplers.length; i++) {
    var uniform = this.samplers[i];
    var tex = uniform.texture;
    if (tex === undefined) {
      // user hasn't yet supplied a texture for this slot.
      // (or there may not be one--maybe just lighting),
      // so we supply a default texture instead.
      tex = this._renderer._getEmptyTexture();
    }
    gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
    tex.bindTexture();
    tex.update();
    gl.uniform1i(uniform.location, uniform.samplerIndex);
  }
};

p5.Shader.prototype.unbindTextures = function () {
  // TODO: migrate stuff from material.js here
  // - OR - have material.js define this function
};

p5.Shader.prototype._setMatrixUniforms = function() {
  this.setUniform('uProjectionMatrix', this._renderer.uPMatrix.mat4);
  this.setUniform('uModelViewMatrix', this._renderer.uMVMatrix.mat4);
  if(this === this._renderer.curFillShader) {
    this._renderer.uNMatrix.inverseTranspose(this._renderer.uMVMatrix);
    this.setUniform('uNormalMatrix', this._renderer.uNMatrix.mat3);
  }
};

p5.Shader.prototype._setViewportUniform = function() {
  this.setUniform('uViewport', this._renderer.GL.getParameter(this._renderer.GL.VIEWPORT));
};

/**
 * @method useProgram
 * @chainable
 * @private
 */
p5.Shader.prototype.useProgram = function () {
  var gl = this._renderer.GL;
  gl.useProgram(this._glProgram);
  return this;
};

/**
 * Wrapper around gl.uniform functions.
 * As we store uniform info in the shader we can use that
 * to do type checking on the supplied data and call
 * the appropriate function.
 * @method setUniform
 * @chainable
 * @param {String} uniformName the name of the uniform in the
 * shader program
 * @param {Object} data the data to be associated with that uniform; type
 * varies (could be a single numerical value, array, matrix, or
 * texture / sampler reference)
 */
p5.Shader.prototype.setUniform = function(uniformName, data)
{
  //@todo update all current gl.uniformXX calls

  var gl = this._renderer.GL;
  // todo: is this safe to do here?
  // todo: store the values another way?
  this.useProgram();

  // TODO BIND?
  var uniform = this.uniforms[uniformName];
  if(!uniform) {
    //@todo warning?
    return;
  }
  var location = uniform.location;

  switch(uniform.type){
    case gl.BOOL:
      if(data === true) {
        gl.uniform1i(location, 1);
      }
      else {
        gl.uniform1i(location, 0);
      }
      break;
    case gl.INT:
      gl.uniform1i(location, data);
      break;
    case gl.FLOAT:
      if(uniform.size > 1){
        gl.uniform1fv(location, data);
      }
      else{
        gl.uniform1f(location, data);
      }
      break;
    case gl.FLOAT_MAT3:
      gl.uniformMatrix3fv(location, false, data);
      break;
    case gl.FLOAT_MAT4:
      gl.uniformMatrix4fv(location, false, data);
      break;
    case gl.FLOAT_VEC2:
      if(uniform.size > 1){
        gl.uniform2fv(location, data);
      }
      else{
        gl.uniform2f(location, data[0], data[1]);
      }
      break;
    case gl.FLOAT_VEC3:
      if(uniform.size > 1){
        gl.uniform3fv(location, data);
      }
      else{
        gl.uniform3f(location, data[0], data[1], data[2]);
      }
      break;
    case gl.FLOAT_VEC4:
      if(uniform.size > 1){
        gl.uniform4fv(location, data);
      }
      else{
        gl.uniform4f(location, data[0], data[1], data[2], data[3]);
      }
      break;
    case gl.SAMPLER_2D:
      gl.activeTexture(gl.TEXTURE0 + uniform.samplerIndex);
      uniform.texture = this._renderer.getTexture(data);
      gl.uniform1i(uniform.location, uniform.samplerIndex);
      break;
    //@todo complete all types
  }
  return this;
};

/* NONE OF THIS IS FAST OR EFFICIENT BUT BEAR WITH ME
 *
 * these shader "type" query methods are used by various
 * facilities of the renderer to determine if changing
 * the shader type for the required action (for example,
 * do we need to load the default lighting shader if the
 * current shader cannot handle lighting?)
 *
 **/

p5.Shader.prototype.isLightShader = function () {
  return this.uniforms.uUseLighting !== undefined ||
    this.uniforms.uAmbientLightCount !== undefined ||
    this.uniforms.uDirectionalLightCount !== undefined ||
    this.uniforms.uPointLightCount !== undefined ||
    this.uniforms.uAmbientColor !== undefined ||
    this.uniforms.uDirectionalColor !== undefined ||
    this.uniforms.uPointLightLocation !== undefined ||
    this.uniforms.uPointLightColor !== undefined ||
    this.uniforms.uLightingDirection !== undefined ||
    this.uniforms.uSpecular !== undefined;
};

p5.Shader.prototype.isTextureShader = function () {
  return this.samplerIndex > 0;
};

p5.Shader.prototype.isColorShader = function () {
  return this.attributes.aVertexColor !== undefined ||
    this.uniforms.uMaterialColor !== undefined;
};

p5.Shader.prototype.isTexLightShader = function () {
  return this.isLightShader() && this.isTextureShader();
};

p5.Shader.prototype.isStrokeShader = function () {
  return this.uniforms.uStrokeWeight !== undefined;
};

/**
 * @method enableAttrib
 * @chainable
 * @private
 */
p5.Shader.prototype.enableAttrib = function(loc, size,
  type, normalized, stride, offset) {
  var gl = this._renderer.GL;
  if(loc !== -1) {
    gl.enableVertexAttribArray(loc);
    gl.vertexAttribPointer(loc, size, type, normalized, stride, offset);
  }
  return this;
};

module.exports = p5.Shader;
<|endoftext|>


<commit_before>jQuery.getScript = function(url, callback, cache) {
    jQuery.ajax({ type: "GET", url: url, success: callback, dataType: "script", cache: cache });
};

function tubepress_init(baseUrl) {
	tubepress_load_embedded_js(baseUrl);
    tubepress_load_players(baseUrl);
    tubepress_attach_listeners();
}

function tubepress_attach_listeners()
{
	jQuery("a[id^='tubepress_']").click(function () {
		var rel_split    = jQuery(this).attr("rel").split("_");
		var galleryId    = rel_split[3];
		var playerName   = rel_split[2];
		var embeddedName = rel_split[1];
		var videoId = jQuery(this).attr("id").substring(16, 27);

        _tubepress_swap_embedded(galleryId, videoId, embeddedName);
        _tubepress_call_player_js(galleryId, videoId, embeddedName, playerName);
    });
}

function _tubepress_swap_embedded(galleryId, videoId, embeddedName) {
    var matcher = window["tubepress_" + embeddedName + "_matcher"]();
    var wrapper = jQuery("#tubepress_embedded_object_" + galleryId);
    if (wrapper.html() != null) {
        var oldVideoId = wrapper.html().match(matcher)[1];
        wrapper.html(wrapper.html().replace(oldVideoId, videoId));
    }
}

function _tubepress_call_player_js(galleryId, videoId, embeddedName, playerName) {
    var playerFunctionName = "tubepress_" + playerName + "_player";
    window[playerFunctionName](galleryId, videoId);
}

function tubepress_load_players(baseUrl) {
	var playerNames = _tubepress_rel_parser(2);
    for(var i = 0; i < playerNames.length; i++) {
    	var name = playerNames[i];
        jQuery.getScript(baseUrl + "/ui/players/" + name + "/" + name + ".js",
        	_tubepress_player_loaded(name, baseUrl) , true);
    }
}

function _tubepress_player_loaded(playerName, baseUrl) {
	var funcName = 'tubepress_' + playerName + '_player_init';
	var f = function() { window[funcName](baseUrl); }
	_tubepress_call_when_true(function() { return typeof window[funcName] == 'function'; }, f);
}

function tubepress_load_embedded_js(baseUrl) {
    var embeddedNames = _tubepress_rel_parser(1);
    for(var i = 0; i < embeddedNames.length; i++) {
        jQuery.getScript(baseUrl + "/ui/embedded/" + embeddedNames[i] + "/" + embeddedNames[i] + ".js", function() {}, true);
    }
}

function _tubepress_rel_parser(index) {
    var returnValue = [];
    jQuery("a[rel^='tubepress_']").each( function() {
        var thisName = jQuery(this).attr("rel").split("_")[index];
        if (jQuery.inArray(thisName, returnValue) == -1) {
            returnValue.push(thisName);
        }
    });
    return returnValue;
}

function _tubepress_call_when_true(test, callback) {
	if (!test()) {
		setTimeout(function() {_tubepress_call_when_true(test, callback);}, 400);
		return;
	}
	callback();
}

function _tubepress_get_wait_call(scriptPath, test, callback) {
	jQuery.getScript(scriptPath, function() {
		_tubepress_call_when_true(test, callback);
    }, true);
}
<commit_msg>Embedded swap works with both IE and FF for the first time<commit_after>jQuery.getScript = function(url, callback, cache) {
    jQuery.ajax({ type: "GET", url: url, success: callback, dataType: "script", cache: cache });
};

function tubepress_init(baseUrl) {
	tubepress_load_embedded_js(baseUrl);
    tubepress_load_players(baseUrl);
    tubepress_attach_listeners();
}

function tubepress_attach_listeners()
{
	jQuery("a[id^='tubepress_']").click(function () {
		var rel_split    = jQuery(this).attr("rel").split("_");
		var galleryId    = rel_split[3];
		var playerName   = rel_split[2];
		var embeddedName = rel_split[1];
		var videoId = jQuery(this).attr("id").substring(16, 27);

        _tubepress_swap_embedded(galleryId, videoId, embeddedName);
        _tubepress_call_player_js(galleryId, videoId, embeddedName, playerName);
    });
}

/**
 * This function is very carefully constructed to work with both IE and FF.
 * Modify at your own risk!!
 *
 * @param galleryId    The unique gallery ID containing the embedded object
 *                      to swap
 * @param videoId      The "new" YouTube video ID
 * @param embeddedName Longtail, YouTube, etc
 * @return void
 */
function _tubepress_swap_embedded(galleryId, videoId, embeddedName) {

	var wrapperId = "#tubepress_embedded_object_" + galleryId;
    var wrapper = jQuery(wrapperId);
    if (wrapper.html() != "") {

    	/* grab the matcher for the embedded player */
    	var matcher = window["tubepress_" + embeddedName + "_matcher"]();
    	var oldVideoId = wrapper.html().match(matcher)[1];

    	/* save the params but remove them from the DOM for now */
    	var params = jQuery(wrapperId + " > object > param");
    	params.remove();

    	/* replace the video ID inside the object tag */
    	var newHtml = wrapper.html().replace(oldVideoId, videoId);

    	/* chop off the closing </object> */
    	newHtml = newHtml.substring(0, newHtml.length - 9);

    	/* now add back the params, but this time with the new video ID */
    	params.each(function() {
        	newHtml += '<param name="' + this.name + '" value="' + this.value.replace(oldVideoId, videoId) + '" />';
        });

    	/* re-close the object */
    	newHtml += '</object>';

    	/* add it back in */
    	wrapper.html(newHtml);
    }
}

function _tubepress_call_player_js(galleryId, videoId, embeddedName, playerName) {
    var playerFunctionName = "tubepress_" + playerName + "_player";
    window[playerFunctionName](galleryId, videoId);
}

function tubepress_load_players(baseUrl) {
	var playerNames = _tubepress_rel_parser(2);
    for(var i = 0; i < playerNames.length; i++) {
    	var name = playerNames[i];
        jQuery.getScript(baseUrl + "/ui/players/" + name + "/" + name + ".js",
        	_tubepress_player_loaded(name, baseUrl) , true);
    }
}

function _tubepress_player_loaded(playerName, baseUrl) {
	var funcName = 'tubepress_' + playerName + '_player_init';
	var f = function() { window[funcName](baseUrl); }
	_tubepress_call_when_true(function() { return typeof window[funcName] == 'function'; }, f);
}

function tubepress_load_embedded_js(baseUrl) {
    var embeddedNames = _tubepress_rel_parser(1);
    for(var i = 0; i < embeddedNames.length; i++) {
        jQuery.getScript(baseUrl + "/ui/embedded/" + embeddedNames[i] + "/" + embeddedNames[i] + ".js", function() {}, true);
    }
}

function _tubepress_rel_parser(index) {
    var returnValue = [];
    jQuery("a[rel^='tubepress_']").each( function() {
        var thisName = jQuery(this).attr("rel").split("_")[index];
        if (jQuery.inArray(thisName, returnValue) == -1) {
            returnValue.push(thisName);
        }
    });
    return returnValue;
}

function _tubepress_call_when_true(test, callback) {
	if (!test()) {
		setTimeout(function() {_tubepress_call_when_true(test, callback);}, 400);
		return;
	}
	callback();
}

function _tubepress_get_wait_call(scriptPath, test, callback) {
	jQuery.getScript(scriptPath, function() {
		_tubepress_call_when_true(test, callback);
    }, true);
}
<|endoftext|>


<commit_before>var _ = require('underscore');
var WidgetModel = require('./widgets/widget-model');
var CategoryWidgetModel = require('./widgets/category/category-widget-model');
var HistogramWidgetModel = require('./widgets/histogram/histogram-widget-model');
var TimeSeriesWidgetModel = require('./widgets/time-series/time-series-widget-model');

/**
 * Public API to interact with dashboard widgets.
 */
var WidgetsService = function (widgetsCollection, dataviews) {
  this._widgetsCollection = widgetsCollection;
  this._dataviews = dataviews;
};

WidgetsService.prototype.getCollection = function () {
  return this._widgetsCollection;
};

WidgetsService.prototype.get = function (id) {
  return this._widgetsCollection.get(id);
};

WidgetsService.prototype.getList = function () {
  return this._widgetsCollection.models;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.title Title rendered on the widget view
 * @param {String} attrs.column Name of column to use to aggregate
 * @param {String} attrs.aggregation Name of aggregation operation to apply to get categories
 *   can be any of ['sum', 'count']. Default is 'count'
 * @param {String} attrs.aggregation_column column to be used for the aggregation operation
 *  it only applies for sum operations.
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @return {CategoryWidgetModel}
 */
WidgetsService.prototype.createCategoryModel = function (attrs, layer, state, opts) {
  _checkProperties(attrs, ['title']);
  attrs = _.extend(attrs, state, {hasInitialState: this._widgetsCollection.hasInitialState()}); // Will overwrite preset attributes with the ones passed on the state
  var dataviewModel = this._dataviews.createCategoryModel(layer, attrs);

  var attrsNames = ['id', 'title', 'order', 'collapsed', 'prefix', 'suffix', 'show_stats', 'style', 'hasInitialState'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new CategoryWidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  }, opts);
  widgetModel.setInitialState(state);
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.title Title rendered on the widget view
 * @param {String} attrs.column Name of column
 * @param {Number} attrs.bins Count of bins
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @return {WidgetModel}
 */
WidgetsService.prototype.createHistogramModel = function (attrs, layer, state, opts) {
  _checkProperties(attrs, ['title']);
  var dataAttrs = _.extend(attrs, state, {hasInitialState: this._widgetsCollection.hasInitialState()}); // Will overwrite preset attributes with the ones passed on the state
  var dataviewModel = this._dataviews.createHistogramModel(layer, dataAttrs);

  var attrsNames = ['id', 'title', 'order', 'collapsed', 'bins', 'show_stats', 'normalized', 'style', 'hasInitialState'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  widgetAttrs.type = 'histogram';
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new HistogramWidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  }, opts);
  widgetModel.setInitialState(state);
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.title Title rendered on the widget view
 * @param {String} attrs.column Name of column
 * @param {String} attrs.operation Name of operation to use, can be any of ['min', 'max', 'avg', 'sum']
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @return {CategoryWidgetModel}
 */
WidgetsService.prototype.createFormulaModel = function (attrs, layer, state) {
  _checkProperties(attrs, ['title']);
  attrs = _.extend(attrs, state, {hasInitialState: this._widgetsCollection.hasInitialState()}); // Will overwrite preset attributes with the ones passed on the state
  var dataviewModel = this._dataviews.createFormulaModel(layer, attrs);

  var attrsNames = ['id', 'title', 'order', 'collapsed', 'prefix', 'suffix', 'show_stats', 'description', 'hasInitialState'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  widgetAttrs.type = 'formula';
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new WidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  });
  widgetModel.setInitialState(state);
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.title Title rendered on the widget view
 * @param {Array} attrs.columns Names of columns
 * @param {Number} attrs.bins Count of bins
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @return {WidgetModel}
 */
WidgetsService.prototype.createListModel = function (attrs, layer) {
  _checkProperties(attrs, ['title', 'columns_title']);

  var dataviewModel = this._dataviews.createListModel(layer, attrs);

  var attrsNames = ['id', 'title', 'order', 'columns_title', 'show_stats'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  widgetAttrs.type = 'list';
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new WidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  });
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.column Name of column that contains
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @param {Number} bins
 * @return {WidgetModel}
 */
WidgetsService.prototype.createTimeSeriesModel = function (attrs, layer, state, opts) {
  // TODO will other kind really work for a time-series?
  attrs.column_type = attrs.column_type || 'date';
  var dataviewModel = this._dataviews.createHistogramModel(layer, attrs);

  var attrsNames = ['id', 'style'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  widgetAttrs.type = 'time-series';
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new TimeSeriesWidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  }, opts);
  widgetModel.setInitialState(state);
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

WidgetsService.prototype.setWidgetsState = function (state) {
  this._widgetsCollection.setStates(state);
};

function _checkProperties (obj, propertiesArray) {
  _.each(propertiesArray, function (prop) {
    if (obj[prop] === undefined) {
      throw new Error(prop + ' is required');
    }
  });
}

module.exports = WidgetsService;
<commit_msg>Create options autostyle related.<commit_after>var _ = require('underscore');
var WidgetModel = require('./widgets/widget-model');
var CategoryWidgetModel = require('./widgets/category/category-widget-model');
var HistogramWidgetModel = require('./widgets/histogram/histogram-widget-model');
var TimeSeriesWidgetModel = require('./widgets/time-series/time-series-widget-model');

var WIDGETSTYLEPARAMS = {
  auto_style_allowed: 'autoStyleEnabled'
};

// We create an object with options off the attributes
var makeWidgetStyleOptions = function (attrs) {
  return _.reduce(WIDGETSTYLEPARAMS, function (memo, value, key) {
    if (attrs[key] !== undefined) {
      memo[value] = attrs[key];
      return memo;
    }
  }, {});
}
/**
 * Public API to interact with dashboard widgets.
 */
var WidgetsService = function (widgetsCollection, dataviews) {
  this._widgetsCollection = widgetsCollection;
  this._dataviews = dataviews;
};

WidgetsService.prototype.getCollection = function () {
  return this._widgetsCollection;
};

WidgetsService.prototype.get = function (id) {
  return this._widgetsCollection.get(id);
};

WidgetsService.prototype.getList = function () {
  return this._widgetsCollection.models;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.title Title rendered on the widget view
 * @param {String} attrs.column Name of column to use to aggregate
 * @param {String} attrs.aggregation Name of aggregation operation to apply to get categories
 *   can be any of ['sum', 'count']. Default is 'count'
 * @param {String} attrs.aggregation_column column to be used for the aggregation operation
 *  it only applies for sum operations.
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @return {CategoryWidgetModel}
 */
WidgetsService.prototype.createCategoryModel = function (attrs, layer, state) {
  _checkProperties(attrs, ['title']);
  attrs = _.extend(attrs, state, {hasInitialState: this._widgetsCollection.hasInitialState()}); // Will overwrite preset attributes with the ones passed on the state
  var dataviewModel = this._dataviews.createCategoryModel(layer, attrs);

  var attrsNames = ['id', 'title', 'order', 'collapsed', 'prefix', 'suffix', 'show_stats', 'style', 'hasInitialState'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  var options = makeWidgetStyleOptions(attrs);

  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new CategoryWidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  }, options);
  widgetModel.setInitialState(state);
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.title Title rendered on the widget view
 * @param {String} attrs.column Name of column
 * @param {Number} attrs.bins Count of bins
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @return {WidgetModel}
 */
WidgetsService.prototype.createHistogramModel = function (attrs, layer, state, opts) {
  _checkProperties(attrs, ['title']);
  var dataAttrs = _.extend(attrs, state, {hasInitialState: this._widgetsCollection.hasInitialState()}); // Will overwrite preset attributes with the ones passed on the state
  var dataviewModel = this._dataviews.createHistogramModel(layer, dataAttrs);

  var attrsNames = ['id', 'title', 'order', 'collapsed', 'bins', 'show_stats', 'normalized', 'style', 'hasInitialState'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  var options = makeWidgetStyleOptions(attrs);

  widgetAttrs.type = 'histogram';
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new HistogramWidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  }, options);
  widgetModel.setInitialState(state);
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.title Title rendered on the widget view
 * @param {String} attrs.column Name of column
 * @param {String} attrs.operation Name of operation to use, can be any of ['min', 'max', 'avg', 'sum']
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @return {CategoryWidgetModel}
 */
WidgetsService.prototype.createFormulaModel = function (attrs, layer, state) {
  _checkProperties(attrs, ['title']);
  attrs = _.extend(attrs, state, {hasInitialState: this._widgetsCollection.hasInitialState()}); // Will overwrite preset attributes with the ones passed on the state
  var dataviewModel = this._dataviews.createFormulaModel(layer, attrs);

  var attrsNames = ['id', 'title', 'order', 'collapsed', 'prefix', 'suffix', 'show_stats', 'description', 'hasInitialState'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  widgetAttrs.type = 'formula';
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new WidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  });
  widgetModel.setInitialState(state);
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.title Title rendered on the widget view
 * @param {Array} attrs.columns Names of columns
 * @param {Number} attrs.bins Count of bins
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @return {WidgetModel}
 */
WidgetsService.prototype.createListModel = function (attrs, layer) {
  _checkProperties(attrs, ['title', 'columns_title']);

  var dataviewModel = this._dataviews.createListModel(layer, attrs);

  var attrsNames = ['id', 'title', 'order', 'columns_title', 'show_stats'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  widgetAttrs.type = 'list';
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new WidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  });
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

/**
 * @param {Object} attrs
 * @param {String} attrs.column Name of column that contains
 * @param {Object} layer Instance of a layer model (cartodb.js)
 * @param {Number} bins
 * @return {WidgetModel}
 */
WidgetsService.prototype.createTimeSeriesModel = function (attrs, layer, state, opts) {
  // TODO will other kind really work for a time-series?
  attrs.column_type = attrs.column_type || 'date';
  var dataviewModel = this._dataviews.createHistogramModel(layer, attrs);

  var attrsNames = ['id', 'style'];
  var widgetAttrs = _.pick(attrs, attrsNames);
  widgetAttrs.type = 'time-series';
  widgetAttrs.attrsNames = attrsNames;

  var widgetModel = new TimeSeriesWidgetModel(widgetAttrs, {
    dataviewModel: dataviewModel
  }, opts);
  widgetModel.setInitialState(state);
  this._widgetsCollection.add(widgetModel);

  return widgetModel;
};

WidgetsService.prototype.setWidgetsState = function (state) {
  this._widgetsCollection.setStates(state);
};

function _checkProperties (obj, propertiesArray) {
  _.each(propertiesArray, function (prop) {
    if (obj[prop] === undefined) {
      throw new Error(prop + ' is required');
    }
  });
}

module.exports = WidgetsService;
<|endoftext|>