<commit_before>/** @jsx React.DOM */

var PlayerSelector = React.createClass({
	render: function() {
		var rows = [];
		this.props.players.forEach(function(player) {
			rows.push(
				<option value={player.Name} key={player.Name}>
					{player.Name}
				</option>
			);
		}.bind(this));
		return (
			<select onChange={this.props.onChangeFunction} value={this.props.selectedPlayer !== null? this.props.selectedPlayer.Name : ""}>
				<option disabled value="">Select a Player</option>
				{rows}
			</select>
		);
	}
});

var PlayerInjuries = React.createClass({
	updateData: function(event) {
		appActions.updateInjuries(this.props.player.Name, this.refs.injuryText.getDOMNode().value);
		this.refs.injuryText.getDOMNode().value = "";
	},
	render: function() {
		var rows = []
		if (this.props.player !== null && this.props.player.Injuries !== null && this.props.player.Injuries.length > 0) {
			this.props.player.Injuries.forEach(function(injury) {
				rows.push(

{injury}

				);
			});
		} else {
			rows.push(
--None--
)
		}
		var adminCols = [];
		if (this.props.admin) {
			adminCols = (
				<Col >
					<input type="text" ref="injuryText" />
					<Button bsStyle="primary" onClick={this.updateData}>Update</Button>
				</Col>
			);
		}
		return (
			<Grid>
				<Row>
					<Col xs={this.props.admin? 6 : 12}>

Injuries

{rows}

					</Col>
					{adminCols}
				</Row>
			</Grid>
		);
	}
});

var PlayerBondDetail = React.createClass({
	deleteBond: function(event) {
		appActions.deleteActiveBond(this.props.bond.Warcaster,
									this.props.bond.Warjack,
									this.props.bond.BondNumber,
									this.props.bond.BondName,
									this.props.playerName);
	},
	render: function() {
		var deleteButton = [];
		if (this.props.admin) {
			deleteButton = (
				<Button bsStyle="danger" bsSize="xsmall" onClick={this.deleteBond}>Delete</Button>
			);
		}
		return (

				{this.props.bond.Warcaster}
				{this.props.bond.Warjack}
				{this.props.bond.BondName}
				{this.props.bond.BondNumber}
				{deleteButton}

		);
	}
});

var PlayerBonds = React.createClass({
	submitBond: function(event) {
		var warcasterName = this.refs.warcasterInput.getDOMNode().value;
		var warjackName = this.refs.warjackInput.getDOMNode().value;
		var bondText = this.refs.bondNameInput.getDOMNode().value;
		var bondNumber = this.refs.bondNumberInput.getDOMNode().value;
		appActions.addActiveBond(warcasterName, warjackName, bondText, bondNumber, this.props.player.Name);
		this.refs.warcasterInput.getDOMNode().value = "";
		this.refs.warjackInput.getDOMNode().value = "";
		this.refs.bondNameInput.getDOMNode().value = "";
		this.refs.bondNumberInput.getDOMNode().value = "";
	},
	render: function() {
		var bonds = [];
		if (this.props.player !== null && this.props.player.Bonds !== null && this.props.player.Bonds.ActiveBonds !== null) {
			for (i = 0; i < this.props.player.Bonds.ActiveBonds.length; i++) {
				bonds.push(
					<PlayerBondDetail bond={this.props.player.Bonds.ActiveBonds[i]} playerName={this.props.player.Name} key={i} admin={this.props.admin} />
				);
			}
		}
		if (bonds.length === 0) {
			bonds.push(

--None--

			);
		}
		var editingPanel = [];
		adminHeader = [];
		if (this.props.admin) {
			adminHeader = (
				Delete?
			);
			editingPanel = (

					<input type="text" ref="warcasterInput" placeholder="Warcaster" />
					<input type="text" ref="warjackInput" placeholder="Warjack" />
					<input type="Text" ref="bondNameInput" placeholder="Bond Name" />
					<input type="number" ref="bondNumberInput" placeholder="Number" />
					<Button bsStyle="primary" onClick={this.submitBond}>Submit</Button>

			);
		}
		//TODO: adding or deleting bonds
		return (
			<Grid>
				<Row>
					<Col xs={this.props.admin? 6 : 12}>

								Warcaster/Warlock
								Warjack/Warbeast
								Bond Name
								Bond Number
								{adminHeader}

								{bonds}
								{editingPanel}

					</Col>
				</Row>
			</Grid>
		);
	}
});

var PlayerPotentialBondDetail = React.createClass({
	deleteBond: function(event) {
		appActions.deletePotentialBond(this.props.bond.Warcaster,
									   this.props.bond.Warjack,
									   this.props.bond.Bonus,
									   this.props.playerName);
	},
	incrementBond: function(event) {
		appActions.incrementPotentialBond(this.props.bond.Warcaster,
									   this.props.bond.Warjack,
									   this.props.bond.Bonus,
									   this.props.playerName);
	},
	render: function() {
		var deleteButton = [];
		var incrementButton = [];
		if (this.props.admin) {
			deleteButton = (
				<Button bsStyle="danger" bsSize="xsmall" onClick={this.deleteBond}>Delete</Button>
			);
			incrementButton = (
				<Button bsSize="xsmall" onClick={this.incrementBond}>+</Button>
			);
		}
		return (

				{this.props.bond.Warcaster}
				{this.props.bond.Warjack}
				{this.props.bond.Bonus}{incrementButton}
				{deleteButton}

		);
	}
});

var PlayerPotentialBonds = React.createClass({
	submitBond: function(event) {
		var warcasterName = this.refs.warcasterPotential.getDOMNode().value;
		var warjackName = this.refs.warjackPotential.getDOMNode().value;
		var bonus = this.refs.bonusPotential.getDOMNode().value;
		appActions.addPotentialBond(warcasterName, warjackName, bonus, this.props.player.Name);
		this.refs.warcasterPotential.getDOMNode().value = "";
		this.refs.warjackPotential.getDOMNode().value = "";
		this.refs.bonusPotential.getDOMNode().value = "";
	},
	render: function() {
		var bonds = [];
		if (this.props.player !== null && this.props.player.Bonds !== null && this.props.player.Bonds.PotentialBonds !== null) {
			for (i = 0; i < this.props.player.Bonds.PotentialBonds.length; i++) {
				bonds.push(
					<PlayerPotentialBondDetail bond={this.props.player.Bonds.PotentialBonds[i]} key={i} admin={this.props.admin} playerName={this.props.player.Name}/>
				);
			}
		}
		if (bonds.length === 0) {
			bonds.push(

--None--

			);
		}
		var adminHeader = [];
		var editingPanel = []
		if (this.props.admin) {
			adminHeader = (
				Delete?
			);
			editingPanel = (

					<input type="text" ref="warcasterPotential" placeholder="Warcaster" />
					<input type="text" ref="warjackPotential" placeholder="Warjack" />
					<input type="number" ref="bonusPotential" placeholder="Bonus" />
					<Button bsStyle="primary" onClick={this.submitBond}>Submit</Button>

			);
		}
		//TODO: adding or deleting bonds
		return (
			<Grid>
				<Row>
					<Col xs={12}>

								Warcaster/Warlock
								Warjack/Warbeast
								Bonus
								{adminHeader}

								{bonds}
								{editingPanel}

					</Col>
				</Row>
			</Grid>
		);
	}
});

var PlayerEditorPanel = React.createClass({
	mixins: [Reflux.ListenerMixin],
	onStatusChange: function(data) {
		var selectedPlayer = this.state.selectedPlayer;
		if (selectedPlayer === null) {
			selectedPlayer = data.Players[0];
		}
		this.setState({
			season: data,
			selectedPlayer: this.getSelectedPlayer(selectedPlayer.Name, data)
		});
	},
	getInitialState: function() {
		return {
			season: window.seasonStore.season,
			selectedPlayer: null,
		};
	},
	playerSelectionChange: function(event) {
		appActions.viewPlayer(event.target.value);
	},
	componentDidMount: function() {
		this.listenTo(window.seasonStore, this.onStatusChange);
		this.listenTo(window.viewPlayerStore, this.viewPlayer);
	},
	getSelectedPlayer: function(playerName, season) {
		for (var i = 0; i < this.state.season.Players.length; i++) {
			if (season.Players[i].Name === playerName) {
				return season.Players[i];
			}
		}
	},
	viewPlayer: function(playerName) {
		this.setState({ selectedPlayer: this.getSelectedPlayer(playerName, this.state.season) });
	},
	render: function() {
		var admin = this.props.admin;
		var players = [];
		var tabbedArea =
No player selected.
;
		if (this.state.season !== null) {
			players = this.state.season.Players;
		}
		if (this.state.selectedPlayer) {
			tabbedArea =

					<PlayerCell player={this.state.selectedPlayer} noLink={true} />
					<TabbedArea defaultActiveKey={1}>
						<TabPane key={1} tab="Injuries">
							<PlayerInjuries player={this.state.selectedPlayer} admin={admin} />
						</TabPane>
						<TabPane key={2} tab="Bonds">
							<PlayerBonds player={this.state.selectedPlayer} admin={admin} />
						</TabPane>
						<TabPane key={3} tab="Potential Bonds">
							<PlayerPotentialBonds player={this.state.selectedPlayer} admin={admin} />
						</TabPane>
					</TabbedArea>

;
		}

		return (
			<Grid id="player-info">
				<Row>
					<PlayerSelector players={players}
									selectedPlayer={this.state.selectedPlayer}
									onChangeFunction={this.playerSelectionChange} />
					{tabbedArea}
				</Row>
			</Grid>
		);
	}
});
<commit_msg>Added a schedule tab to player data.<commit_after>/** @jsx React.DOM */

var PlayerSchedule = React.createClass({
	render: function() {
		var rows = [];
		var player = this.props.player
		if (!player) {
			return
No data found
;
		} else {
			this.props.season.Weeks.forEach(function(week, weekIndex) {
				var weekRows = []
				var weekText = week.Number + " (" + week.PlayDate + ")"
				var scenarios = week.Scenarios[0] + " or " + week.Scenarios[1]
				week.Games.forEach(function(game) {
					if(game.PlayerIds.indexOf(player.Name) != -1) {
						var opponent = game.Players.filter(function(p) { return p.Name != player.Name })[0];
						weekRows.push(
{weekText}	<PlayerCell player={opponent} />	{scenarios}	{game.WinnerId}
);
					}
				});
				if(weekRows.length == 0) {
					weekRows = [
{weekText}	Bye	{scenarios}	{player.Name}
];
				}
				rows = rows.concat(weekRows);
			});
		}
		return (
			<Grid>
				<Row>
					<Col xs={12}>

									Week
									Opponent
									Scenario
									Winner

								{rows}

					</Col>
				</Row>
			</Grid>
		);
	}
});

var PlayerSelector = React.createClass({
	render: function() {
		var rows = [];
		this.props.players.forEach(function(player) {
			rows.push(
				<option value={player.Name} key={player.Name}>
					{player.Name}
				</option>
			);
		}.bind(this));
		return (
			<select onChange={this.props.onChangeFunction} value={this.props.selectedPlayer !== null? this.props.selectedPlayer.Name : ""}>
				<option disabled value="">Select a Player</option>
				{rows}
			</select>
		);
	}
});

var PlayerInjuries = React.createClass({
	updateData: function(event) {
		appActions.updateInjuries(this.props.player.Name, this.refs.injuryText.getDOMNode().value);
		this.refs.injuryText.getDOMNode().value = "";
	},
	render: function() {
		var rows = []
		if (this.props.player !== null && this.props.player.Injuries !== null && this.props.player.Injuries.length > 0) {
			this.props.player.Injuries.forEach(function(injury) {
				rows.push(

{injury}

				);
			});
		} else {
			rows.push(
--None--
)
		}
		var adminCols = [];
		if (this.props.admin) {
			adminCols = (
				<Col >
					<input type="text" ref="injuryText" />
					<Button bsStyle="primary" onClick={this.updateData}>Update</Button>
				</Col>
			);
		}
		return (
			<Grid>
				<Row>
					<Col xs={this.props.admin? 6 : 12}>

Injuries

{rows}

					</Col>
					{adminCols}
				</Row>
			</Grid>
		);
	}
});

var PlayerBondDetail = React.createClass({
	deleteBond: function(event) {
		appActions.deleteActiveBond(this.props.bond.Warcaster,
									this.props.bond.Warjack,
									this.props.bond.BondNumber,
									this.props.bond.BondName,
									this.props.playerName);
	},
	render: function() {
		var deleteButton = [];
		if (this.props.admin) {
			deleteButton = (
				<Button bsStyle="danger" bsSize="xsmall" onClick={this.deleteBond}>Delete</Button>
			);
		}
		return (

				{this.props.bond.Warcaster}
				{this.props.bond.Warjack}
				{this.props.bond.BondName}
				{this.props.bond.BondNumber}
				{deleteButton}

		);
	}
});

var PlayerBonds = React.createClass({
	submitBond: function(event) {
		var warcasterName = this.refs.warcasterInput.getDOMNode().value;
		var warjackName = this.refs.warjackInput.getDOMNode().value;
		var bondText = this.refs.bondNameInput.getDOMNode().value;
		var bondNumber = this.refs.bondNumberInput.getDOMNode().value;
		appActions.addActiveBond(warcasterName, warjackName, bondText, bondNumber, this.props.player.Name);
		this.refs.warcasterInput.getDOMNode().value = "";
		this.refs.warjackInput.getDOMNode().value = "";
		this.refs.bondNameInput.getDOMNode().value = "";
		this.refs.bondNumberInput.getDOMNode().value = "";
	},
	render: function() {
		var bonds = [];
		if (this.props.player !== null && this.props.player.Bonds !== null && this.props.player.Bonds.ActiveBonds !== null) {
			for (i = 0; i < this.props.player.Bonds.ActiveBonds.length; i++) {
				bonds.push(
					<PlayerBondDetail bond={this.props.player.Bonds.ActiveBonds[i]} playerName={this.props.player.Name} key={i} admin={this.props.admin} />
				);
			}
		}
		if (bonds.length === 0) {
			bonds.push(

--None--

			);
		}
		var editingPanel = [];
		adminHeader = [];
		if (this.props.admin) {
			adminHeader = (
				Delete?
			);
			editingPanel = (

					<input type="text" ref="warcasterInput" placeholder="Warcaster" />
					<input type="text" ref="warjackInput" placeholder="Warjack" />
					<input type="Text" ref="bondNameInput" placeholder="Bond Name" />
					<input type="number" ref="bondNumberInput" placeholder="Number" />
					<Button bsStyle="primary" onClick={this.submitBond}>Submit</Button>

			);
		}
		//TODO: adding or deleting bonds
		return (
			<Grid>
				<Row>
					<Col xs={this.props.admin? 6 : 12}>

								Warcaster/Warlock
								Warjack/Warbeast
								Bond Name
								Bond Number
								{adminHeader}

								{bonds}
								{editingPanel}

					</Col>
				</Row>
			</Grid>
		);
	}
});

var PlayerPotentialBondDetail = React.createClass({
	deleteBond: function(event) {
		appActions.deletePotentialBond(this.props.bond.Warcaster,
									   this.props.bond.Warjack,
									   this.props.bond.Bonus,
									   this.props.playerName);
	},
	incrementBond: function(event) {
		appActions.incrementPotentialBond(this.props.bond.Warcaster,
									   this.props.bond.Warjack,
									   this.props.bond.Bonus,
									   this.props.playerName);
	},
	render: function() {
		var deleteButton = [];
		var incrementButton = [];
		if (this.props.admin) {
			deleteButton = (
				<Button bsStyle="danger" bsSize="xsmall" onClick={this.deleteBond}>Delete</Button>
			);
			incrementButton = (
				<Button bsSize="xsmall" onClick={this.incrementBond}>+</Button>
			);
		}
		return (

				{this.props.bond.Warcaster}
				{this.props.bond.Warjack}
				{this.props.bond.Bonus}{incrementButton}
				{deleteButton}

		);
	}
});

var PlayerPotentialBonds = React.createClass({
	submitBond: function(event) {
		var warcasterName = this.refs.warcasterPotential.getDOMNode().value;
		var warjackName = this.refs.warjackPotential.getDOMNode().value;
		var bonus = this.refs.bonusPotential.getDOMNode().value;
		appActions.addPotentialBond(warcasterName, warjackName, bonus, this.props.player.Name);
		this.refs.warcasterPotential.getDOMNode().value = "";
		this.refs.warjackPotential.getDOMNode().value = "";
		this.refs.bonusPotential.getDOMNode().value = "";
	},
	render: function() {
		var bonds = [];
		if (this.props.player !== null && this.props.player.Bonds !== null && this.props.player.Bonds.PotentialBonds !== null) {
			for (i = 0; i < this.props.player.Bonds.PotentialBonds.length; i++) {
				bonds.push(
					<PlayerPotentialBondDetail bond={this.props.player.Bonds.PotentialBonds[i]} key={i} admin={this.props.admin} playerName={this.props.player.Name}/>
				);
			}
		}
		if (bonds.length === 0) {
			bonds.push(

--None--

			);
		}
		var adminHeader = [];
		var editingPanel = []
		if (this.props.admin) {
			adminHeader = (
				Delete?
			);
			editingPanel = (

					<input type="text" ref="warcasterPotential" placeholder="Warcaster" />
					<input type="text" ref="warjackPotential" placeholder="Warjack" />
					<input type="number" ref="bonusPotential" placeholder="Bonus" />
					<Button bsStyle="primary" onClick={this.submitBond}>Submit</Button>

			);
		}
		//TODO: adding or deleting bonds
		return (
			<Grid>
				<Row>
					<Col xs={12}>

								Warcaster/Warlock
								Warjack/Warbeast
								Bonus
								{adminHeader}

								{bonds}
								{editingPanel}

					</Col>
				</Row>
			</Grid>
		);
	}
});

var PlayerEditorPanel = React.createClass({
	mixins: [Reflux.ListenerMixin],
	onStatusChange: function(data) {
		var selectedPlayer = this.state.selectedPlayer;
		if (selectedPlayer === null) {
			selectedPlayer = data.Players[0];
		}
		this.setState({
			season: data,
			selectedPlayer: this.getSelectedPlayer(selectedPlayer.Name, data)
		});
	},
	getInitialState: function() {
		return {
			season: window.seasonStore.season,
			selectedPlayer: null,
		};
	},
	playerSelectionChange: function(event) {
		appActions.viewPlayer(event.target.value);
	},
	componentDidMount: function() {
		this.listenTo(window.seasonStore, this.onStatusChange);
		this.listenTo(window.viewPlayerStore, this.viewPlayer);
	},
	getSelectedPlayer: function(playerName, season) {
		for (var i = 0; i < this.state.season.Players.length; i++) {
			if (season.Players[i].Name === playerName) {
				return season.Players[i];
			}
		}
	},
	viewPlayer: function(playerName) {
		this.setState({ selectedPlayer: this.getSelectedPlayer(playerName, this.state.season) });
	},
	render: function() {
		var admin = this.props.admin;
		var players = [];
		var tabbedArea =
No player selected.
;
		if (this.state.season !== null) {
			players = this.state.season.Players;
		}
		if (this.state.selectedPlayer) {
			tabbedArea =

					<PlayerCell player={this.state.selectedPlayer} noLink={true} />
					<TabbedArea defaultActiveKey={1}>
						<TabPane key={1} tab="Schedule">
							<PlayerSchedule player={this.state.selectedPlayer} season={this.state.season} />
						</TabPane>
						<TabPane key={2} tab="Injuries">
							<PlayerInjuries player={this.state.selectedPlayer} admin={admin} />
						</TabPane>
						<TabPane key={3} tab="Bonds">
							<PlayerBonds player={this.state.selectedPlayer} admin={admin} />
						</TabPane>
						<TabPane key={4} tab="Potential Bonds">
							<PlayerPotentialBonds player={this.state.selectedPlayer} admin={admin} />
						</TabPane>
					</TabbedArea>

;
		}

		return (
			<Grid id="player-info">
				<Row>
					<PlayerSelector players={players}
									selectedPlayer={this.state.selectedPlayer}
									onChangeFunction={this.playerSelectionChange} />
					{tabbedArea}
				</Row>
			</Grid>
		);
	}
});
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// SceneManager
//
// The static class that manages scene transitions.

function SceneManager() {
    throw new Error('This is a static class');
}

/*
 * Gets the current time in ms without on iOS Safari.
 * @private
 */
SceneManager._getTimeInMsWithoutMobileSafari = function() {
    return performance.now();
};

SceneManager._scene             = null;
SceneManager._nextScene         = null;
SceneManager._stack             = [];
SceneManager._stopped           = false;
SceneManager._sceneStarted      = false;
SceneManager._exiting           = false;
SceneManager._previousClass     = null;
SceneManager._backgroundBitmap  = null;
SceneManager._screenWidth       = 816;
SceneManager._screenHeight      = 624;
SceneManager._boxWidth          = 816;
SceneManager._boxHeight         = 624;
SceneManager._deltaTime = 1.0 / 60.0;
if (!Utils.isMobileSafari()) SceneManager._currentTime = SceneManager._getTimeInMsWithoutMobileSafari();
SceneManager._accumulator = 0.0;

SceneManager.run = function(sceneClass) {
    try {
        this.initialize();
        this.goto(sceneClass);
        this.requestUpdate();
    } catch (e) {
        this.catchException(e);
    }
};

SceneManager.initialize = function() {
    this.initGraphics();
    this.checkFileAccess();
    this.initAudio();
    this.initInput();
    this.initNwjs();
    this.checkPluginErrors();
    this.setupErrorHandlers();
};

SceneManager.initGraphics = function() {
    var type = this.preferableRendererType();
    Graphics.initialize(this._screenWidth, this._screenHeight, type);
    Graphics.boxWidth = this._boxWidth;
    Graphics.boxHeight = this._boxHeight;
    Graphics.setLoadingImage('img/system/Loading.png');
    if (Utils.isOptionValid('showfps')) {
        Graphics.showFps();
    }
    if (type === 'webgl') {
        this.checkWebGL();
    }
};

SceneManager.preferableRendererType = function() {
    if (Utils.isOptionValid('canvas')) {
        return 'canvas';
    } else if (Utils.isOptionValid('webgl')) {
        return 'webgl';
    } else {
        return 'auto';
    }
};

SceneManager.shouldUseCanvasRenderer = function() {
    return Utils.isMobileDevice();
};

SceneManager.checkWebGL = function() {
    if (!Graphics.hasWebGL()) {
        throw new Error('Your browser does not support WebGL.');
    }
};

SceneManager.checkFileAccess = function() {
    if (!Utils.canReadGameFiles()) {
        throw new Error('Your browser does not allow to read local files.');
    }
};

SceneManager.initAudio = function() {
    var noAudio = Utils.isOptionValid('noaudio');
    if (!WebAudio.initialize(noAudio) && !noAudio) {
        throw new Error('Your browser does not support Web Audio API.');
    }
};

SceneManager.initInput = function() {
    Input.initialize();
    TouchInput.initialize();
};

SceneManager.initNwjs = function() {
    if (Utils.isNwjs()) {
        var gui = require('nw.gui');
        var win = gui.Window.get();
        if (process.platform === 'darwin' && !win.menu) {
            var menubar = new gui.Menu({ type: 'menubar' });
            var option = { hideEdit: true, hideWindow: true };
            menubar.createMacBuiltin('Game', option);
            win.menu = menubar;
        }
    }
};

SceneManager.checkPluginErrors = function() {
    PluginManager.checkErrors();
};

SceneManager.setupErrorHandlers = function() {
    window.addEventListener('error', this.onError.bind(this));
    document.addEventListener('keydown', this.onKeyDown.bind(this));
};

SceneManager.requestUpdate = function() {
    if (!this._stopped) {
        requestAnimationFrame(this.update.bind(this));
    }
};

SceneManager.update = function() {
    try {
        this.tickStart();
        if (Utils.isMobileSafari()) {
            this.updateInputData();
        }
        this.updateManagers();
        this.updateMain();
        this.tickEnd();
    } catch (e) {
        this.catchException(e);
    }
};

SceneManager.terminate = function() {
    window.close();
};

SceneManager.onError = function(e) {
    console.error(e.message);
    console.error(e.filename, e.lineno);
    try {
        this.stop();
        Graphics.printError('Error', e.message);
        Graphics.printStackTrace(e.stack);
        AudioManager.stopAll();
    } catch (e2) {
    }
};

SceneManager.onKeyDown = function(event) {
    if (!event.ctrlKey && !event.altKey) {
        switch (event.keyCode) {
        case 116:   // F5
            if (Utils.isNwjs()) {
                location.reload();
            }
            break;
        case 119:   // F8
            if (Utils.isNwjs() && Utils.isOptionValid('test')) {
                require('nw.gui').Window.get().showDevTools();
            }
            break;
        }
    }
};

SceneManager.catchException = function(e) {
    if (e instanceof Error) {
        Graphics.printError(e.name, e.message);
        Graphics.printStackTrace(e.stack);
        console.error(e.stack);
    } else {
        Graphics.printError('UnknownError', e);
    }
    AudioManager.stopAll();
    this.stop();
};

SceneManager.tickStart = function() {
    Graphics.tickStart();
};

SceneManager.tickEnd = function() {
    Graphics.tickEnd();
};

SceneManager.updateInputData = function() {
    Input.update();
    TouchInput.update();
};

SceneManager.updateMain = function() {
    if (Utils.isMobileSafari()) {
        this.changeScene();
        this.updateScene();
    } else {
        var newTime = this._getTimeInMsWithoutMobileSafari();
        var fTime = (newTime - this._currentTime) / 1000;
        if (fTime > 0.25) fTime = 0.25;
        this._currentTime = newTime;
        this._accumulator += fTime;
        while (this._accumulator >= this._deltaTime) {
            this.updateInputData();
            this.changeScene();
            this.updateScene();
            this._accumulator -= this._deltaTime;
        }
    }
    this.renderScene();
    this.requestUpdate();
};

SceneManager.updateManagers = function() {
    ImageManager.update();
};

SceneManager.changeScene = function() {
    if (this.isSceneChanging() && !this.isCurrentSceneBusy()) {
        if (this._scene) {
            this._scene.terminate();
            this._scene.detachReservation();
            this._previousClass = this._scene.constructor;
        }
        this._scene = this._nextScene;
        if (this._scene) {
            this._scene.attachReservation();
            this._scene.create();
            this._nextScene = null;
            this._sceneStarted = false;
            this.onSceneCreate();
        }
        if (this._exiting) {
            this.terminate();
        }
    }
};

SceneManager.updateScene = function() {
    if (this._scene) {
        if (!this._sceneStarted && this._scene.isReady()) {
            this._scene.start();
            this._sceneStarted = true;
            this.onSceneStart();
        }
        if (this.isCurrentSceneStarted()) {
            this._scene.update();
        }
    }
};

SceneManager.renderScene = function() {
    if (this.isCurrentSceneStarted()) {
        Graphics.render(this._scene);
    } else if (this._scene) {
        this.onSceneLoading();
    }
};

SceneManager.onSceneCreate = function() {
    Graphics.startLoading();
};

SceneManager.onSceneStart = function() {
    Graphics.endLoading();
};

SceneManager.onSceneLoading = function() {
    Graphics.updateLoading();
};

SceneManager.isSceneChanging = function() {
    return this._exiting || !!this._nextScene;
};

SceneManager.isCurrentSceneBusy = function() {
    return this._scene && this._scene.isBusy();
};

SceneManager.isCurrentSceneStarted = function() {
    return this._scene && this._sceneStarted;
};

SceneManager.isNextScene = function(sceneClass) {
    return this._nextScene && this._nextScene.constructor === sceneClass;
};

SceneManager.isPreviousScene = function(sceneClass) {
    return this._previousClass === sceneClass;
};

SceneManager.goto = function(sceneClass) {
    if (sceneClass) {
        this._nextScene = new sceneClass();
    }
    if (this._scene) {
        this._scene.stop();
    }
};

SceneManager.push = function(sceneClass) {
    this._stack.push(this._scene.constructor);
    this.goto(sceneClass);
};

SceneManager.pop = function() {
    if (this._stack.length > 0) {
        this.goto(this._stack.pop());
    } else {
        this.exit();
    }
};

SceneManager.exit = function() {
    this.goto(null);
    this._exiting = true;
};

SceneManager.clearStack = function() {
    this._stack = [];
};

SceneManager.stop = function() {
    this._stopped = true;
};

SceneManager.prepareNextScene = function() {
    this._nextScene.prepare.apply(this._nextScene, arguments);
};

SceneManager.snap = function() {
    return Bitmap.snap(this._scene);
};

SceneManager.snapForBackground = function() {
    this._backgroundBitmap = this.snap();
    this._backgroundBitmap.blur();
};

SceneManager.backgroundBitmap = function() {
    return this._backgroundBitmap;
};

SceneManager.resume = function() {
    this._stopped = false;
    this.requestUpdate();
    if (!Utils.isMobileSafari()) {
        this._currentTime = this._getTimeInMsWithoutMobileSafari();
        this._accumulator = 0;
    }
};
<commit_msg>remove undefined stack trace<commit_after>//-----------------------------------------------------------------------------
// SceneManager
//
// The static class that manages scene transitions.

function SceneManager() {
    throw new Error('This is a static class');
}

/*
 * Gets the current time in ms without on iOS Safari.
 * @private
 */
SceneManager._getTimeInMsWithoutMobileSafari = function() {
    return performance.now();
};

SceneManager._scene             = null;
SceneManager._nextScene         = null;
SceneManager._stack             = [];
SceneManager._stopped           = false;
SceneManager._sceneStarted      = false;
SceneManager._exiting           = false;
SceneManager._previousClass     = null;
SceneManager._backgroundBitmap  = null;
SceneManager._screenWidth       = 816;
SceneManager._screenHeight      = 624;
SceneManager._boxWidth          = 816;
SceneManager._boxHeight         = 624;
SceneManager._deltaTime = 1.0 / 60.0;
if (!Utils.isMobileSafari()) SceneManager._currentTime = SceneManager._getTimeInMsWithoutMobileSafari();
SceneManager._accumulator = 0.0;

SceneManager.run = function(sceneClass) {
    try {
        this.initialize();
        this.goto(sceneClass);
        this.requestUpdate();
    } catch (e) {
        this.catchException(e);
    }
};

SceneManager.initialize = function() {
    this.initGraphics();
    this.checkFileAccess();
    this.initAudio();
    this.initInput();
    this.initNwjs();
    this.checkPluginErrors();
    this.setupErrorHandlers();
};

SceneManager.initGraphics = function() {
    var type = this.preferableRendererType();
    Graphics.initialize(this._screenWidth, this._screenHeight, type);
    Graphics.boxWidth = this._boxWidth;
    Graphics.boxHeight = this._boxHeight;
    Graphics.setLoadingImage('img/system/Loading.png');
    if (Utils.isOptionValid('showfps')) {
        Graphics.showFps();
    }
    if (type === 'webgl') {
        this.checkWebGL();
    }
};

SceneManager.preferableRendererType = function() {
    if (Utils.isOptionValid('canvas')) {
        return 'canvas';
    } else if (Utils.isOptionValid('webgl')) {
        return 'webgl';
    } else {
        return 'auto';
    }
};

SceneManager.shouldUseCanvasRenderer = function() {
    return Utils.isMobileDevice();
};

SceneManager.checkWebGL = function() {
    if (!Graphics.hasWebGL()) {
        throw new Error('Your browser does not support WebGL.');
    }
};

SceneManager.checkFileAccess = function() {
    if (!Utils.canReadGameFiles()) {
        throw new Error('Your browser does not allow to read local files.');
    }
};

SceneManager.initAudio = function() {
    var noAudio = Utils.isOptionValid('noaudio');
    if (!WebAudio.initialize(noAudio) && !noAudio) {
        throw new Error('Your browser does not support Web Audio API.');
    }
};

SceneManager.initInput = function() {
    Input.initialize();
    TouchInput.initialize();
};

SceneManager.initNwjs = function() {
    if (Utils.isNwjs()) {
        var gui = require('nw.gui');
        var win = gui.Window.get();
        if (process.platform === 'darwin' && !win.menu) {
            var menubar = new gui.Menu({ type: 'menubar' });
            var option = { hideEdit: true, hideWindow: true };
            menubar.createMacBuiltin('Game', option);
            win.menu = menubar;
        }
    }
};

SceneManager.checkPluginErrors = function() {
    PluginManager.checkErrors();
};

SceneManager.setupErrorHandlers = function() {
    window.addEventListener('error', this.onError.bind(this));
    document.addEventListener('keydown', this.onKeyDown.bind(this));
};

SceneManager.requestUpdate = function() {
    if (!this._stopped) {
        requestAnimationFrame(this.update.bind(this));
    }
};

SceneManager.update = function() {
    try {
        this.tickStart();
        if (Utils.isMobileSafari()) {
            this.updateInputData();
        }
        this.updateManagers();
        this.updateMain();
        this.tickEnd();
    } catch (e) {
        this.catchException(e);
    }
};

SceneManager.terminate = function() {
    window.close();
};

SceneManager.onError = function(e) {
    console.error(e.message);
    console.error(e.filename, e.lineno);
    try {
        this.stop();
        Graphics.printError('Error', e.message);
        AudioManager.stopAll();
    } catch (e2) {
    }
};

SceneManager.onKeyDown = function(event) {
    if (!event.ctrlKey && !event.altKey) {
        switch (event.keyCode) {
        case 116:   // F5
            if (Utils.isNwjs()) {
                location.reload();
            }
            break;
        case 119:   // F8
            if (Utils.isNwjs() && Utils.isOptionValid('test')) {
                require('nw.gui').Window.get().showDevTools();
            }
            break;
        }
    }
};

SceneManager.catchException = function(e) {
    if (e instanceof Error) {
        Graphics.printError(e.name, e.message);
        Graphics.printStackTrace(e.stack);
        console.error(e.stack);
    } else {
        Graphics.printError('UnknownError', e);
    }
    AudioManager.stopAll();
    this.stop();
};

SceneManager.tickStart = function() {
    Graphics.tickStart();
};

SceneManager.tickEnd = function() {
    Graphics.tickEnd();
};

SceneManager.updateInputData = function() {
    Input.update();
    TouchInput.update();
};

SceneManager.updateMain = function() {
    if (Utils.isMobileSafari()) {
        this.changeScene();
        this.updateScene();
    } else {
        var newTime = this._getTimeInMsWithoutMobileSafari();
        var fTime = (newTime - this._currentTime) / 1000;
        if (fTime > 0.25) fTime = 0.25;
        this._currentTime = newTime;
        this._accumulator += fTime;
        while (this._accumulator >= this._deltaTime) {
            this.updateInputData();
            this.changeScene();
            this.updateScene();
            this._accumulator -= this._deltaTime;
        }
    }
    this.renderScene();
    this.requestUpdate();
};

SceneManager.updateManagers = function() {
    ImageManager.update();
};

SceneManager.changeScene = function() {
    if (this.isSceneChanging() && !this.isCurrentSceneBusy()) {
        if (this._scene) {
            this._scene.terminate();
            this._scene.detachReservation();
            this._previousClass = this._scene.constructor;
        }
        this._scene = this._nextScene;
        if (this._scene) {
            this._scene.attachReservation();
            this._scene.create();
            this._nextScene = null;
            this._sceneStarted = false;
            this.onSceneCreate();
        }
        if (this._exiting) {
            this.terminate();
        }
    }
};

SceneManager.updateScene = function() {
    if (this._scene) {
        if (!this._sceneStarted && this._scene.isReady()) {
            this._scene.start();
            this._sceneStarted = true;
            this.onSceneStart();
        }
        if (this.isCurrentSceneStarted()) {
            this._scene.update();
        }
    }
};

SceneManager.renderScene = function() {
    if (this.isCurrentSceneStarted()) {
        Graphics.render(this._scene);
    } else if (this._scene) {
        this.onSceneLoading();
    }
};

SceneManager.onSceneCreate = function() {
    Graphics.startLoading();
};

SceneManager.onSceneStart = function() {
    Graphics.endLoading();
};

SceneManager.onSceneLoading = function() {
    Graphics.updateLoading();
};

SceneManager.isSceneChanging = function() {
    return this._exiting || !!this._nextScene;
};

SceneManager.isCurrentSceneBusy = function() {
    return this._scene && this._scene.isBusy();
};

SceneManager.isCurrentSceneStarted = function() {
    return this._scene && this._sceneStarted;
};

SceneManager.isNextScene = function(sceneClass) {
    return this._nextScene && this._nextScene.constructor === sceneClass;
};

SceneManager.isPreviousScene = function(sceneClass) {
    return this._previousClass === sceneClass;
};

SceneManager.goto = function(sceneClass) {
    if (sceneClass) {
        this._nextScene = new sceneClass();
    }
    if (this._scene) {
        this._scene.stop();
    }
};

SceneManager.push = function(sceneClass) {
    this._stack.push(this._scene.constructor);
    this.goto(sceneClass);
};

SceneManager.pop = function() {
    if (this._stack.length > 0) {
        this.goto(this._stack.pop());
    } else {
        this.exit();
    }
};

SceneManager.exit = function() {
    this.goto(null);
    this._exiting = true;
};

SceneManager.clearStack = function() {
    this._stack = [];
};

SceneManager.stop = function() {
    this._stopped = true;
};

SceneManager.prepareNextScene = function() {
    this._nextScene.prepare.apply(this._nextScene, arguments);
};

SceneManager.snap = function() {
    return Bitmap.snap(this._scene);
};

SceneManager.snapForBackground = function() {
    this._backgroundBitmap = this.snap();
    this._backgroundBitmap.blur();
};

SceneManager.backgroundBitmap = function() {
    return this._backgroundBitmap;
};

SceneManager.resume = function() {
    this._stopped = false;
    this.requestUpdate();
    if (!Utils.isMobileSafari()) {
        this._currentTime = this._getTimeInMsWithoutMobileSafari();
        this._accumulator = 0;
    }
};
<|endoftext|>


<commit_before>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * The "add a folder" dialog
 */
var MeasuresModal = Modal.extend({

    type: "filter",
    closeText: "Save",

    events: {
        'submit form': 'save',
        'click .dialog_footer a' : 'call'
    },

    buttons: [
        { text: "OK", method: "save" },
        { text: "Cancel", method: "close" }
    ],

    message: "<form id='measure_form'>" +
                     "
" +
                     "
Name:	" +
                     "<input type='text' class='measure_name' value='Measure Name'></input>
" +
                     "
Formula:	" +
                     "<textarea class='measureFormula'>Measures.[Store Sales] + 100</textarea>
" +
                     "
Format:	" +
                     "<input class='measure_format' type='text' value='#,##0.00'></input>
" +
                     "
</form>",

    measure: null,

    initialize: function(args) {
        var self = this;
        this.workspace = args.workspace;
        this.measure = args.measure;
        _.bindAll(this, "save");

        this.options.title = "Calculated Measure";

        if (this.measure) {
            _.extend(this.options, {
                title: "Custom Filter for " + this.axis
            });
        }

        this.bind( 'open', function( ) {
            if (self.measure) {
            }

        });

        // fix event listening in IE < 9
        if(isIE && isIE < 9) {
            $(this.el).find('form').on('submit', this.save);
        }

    },

    save: function( event ) {
        event.preventDefault( );
        var self = this;
        var measure_name = $(this.el).find('.measure_name').val();
        var measure_formula = $(this.el).find('.measureFormula').val();
        var measure_format = $(this.el).find('.measure_format').val();

        var alert_msg = "";
        if (typeof measure_name == "undefined" || !measure_name) {
            alert_msg += "You have to enter a name for the measure! ";
        }
        if (typeof measure_formula == "undefined" || !measure_formula || measure_formula === "") {
            alert_msg += "You have to enter a MDX formula for the calculated measure! ";
        }
        if (alert_msg !== "") {
            alert(alert_msg);
        } else {
            var m = { name: measure_name, formula: measure_formula, properties: {}, uniqueName: "[Measures]." + measure_name };
            if (measure_format) {
                m.properties.FORMAT_STRING = measure_format;
            }
            self.workspace.query.helper.addCalculatedMeasure(m);
            self.workspace.sync_query();
            this.close();
        }

        return false;
    },

    error: function() {
        $(this.el).find('dialog_body')
            .html("Could not add new folder");
    }

});
<commit_msg>MeasuresModal: calculated measures can now be constructed using a dropdown list of existing measures<commit_after>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * The "add a folder" dialog
 */
var MeasuresModal = Modal.extend({

    type: "filter",
    closeText: "Save",

    mdxFunctions: ['distinct', 'count distinct'],

    events: {
        'submit form': 'save',
        'click .dialog_footer a': 'call',
        'change #Measures': 'addMeasureToCalculationField',
        'click .form_button.mathBtn': 'addMathOperatorToCalculationField'
    },

    buttons: [
        { text: "OK", method: "save" },
        { text: "Cancel", method: "close" }
    ],

    addMeasureTemplate: _.template("<form id='measure_form'>" +
            "
" +
            "
Name:	" +
            "<input type='text' class='measure_name' value='Measure Name'></input>
" +

            "
Measure:	" +
            "" +
            "<select id='Measures' name='MeasuresId'> " +
            "    <option value='' selected='selected'>--select an existing measure--</option> " +
            "    <% _(measures).each(function(m) { %> " +
            "      <option value='<%= m.uniqueName %>'><%= m.name %></option> " +
            "    <% }); %> " +
            "</select> " +
            "
" +

            "
Formula:	" +
            "<textarea class='measureFormula auto-hint' placeholder='Start writing a calculated measure or use the dropdown list'></textarea>
" +

            "
  	" +
            "" +
            " <form> <input type='button' class='form_button mathBtn' style='padding-bottom: 18px;' value='+' id='plusBtn' >  </input>   " +
            " <input type='button' class='form_button mathBtn' style='padding-bottom: 18px;' value='-' id='minusBtn' > </input>  " +
            " <input type='button' class='form_button mathBtn' style='padding-bottom: 18px;' value='*' id='multiplyBtn' >  </input>  " +
            " <input type='button' class='form_button mathBtn' style='padding-bottom: 18px;' value='/' id='divisionBtn' >  </input> " +
            " <input type='button' class='form_button mathBtn' style='padding-bottom: 18px;' value='(' id='leftBracketBtn' >  </input> " +
            " <input type='button' class='form_button mathBtn' style='padding-bottom: 18px;' value=')' id='rightBracketBtn' >  </input> " +

            "</form> 	" +
            "
" +

//            "
Function:	" +
//            "" +
//            "<select id='mdxFunction' name='mdxFunctionId'> " +
//            "    <option value='' selected='selected'>--select a MDX function--</option> " +
//            "    <% _(mdxFunctions).each(function(mdxFunction) { %> " +
//            "      <option value='<%= mdxFunction %>'><%= mdxFunction %></option> " +
//            "    <% }); %> " +
//            "</select> " +
//            "
" +

            "
Format:	" +
            "<input class='measure_format' type='text' value='#,##0.00'></input>
" +
            "
</form>"
    ),

    measure: null,

    initialize: function (args) {
        var self = this;
        this.workspace = args.workspace;
        this.measure = args.measure;

        var cube = this.workspace.selected_cube;
        this.measures = Saiku.session.sessionworkspace.cube[cube].get('data').measures;

        _.bindAll(this, "save");

        this.options.title = "Calculated Measure";

        if (this.measure) {
            _.extend(this.options, {
                title: "Custom Filter for " + this.axis
            });
        }

        this.bind('open', function () {
            if (self.measure) {
            }

        });

        // fix event listening in IE < 9
        if (isIE && isIE < 9) {
            $(this.el).find('form').on('submit', this.save);
        }
        ;

        // Load template
        this.message = this.addMeasureTemplate({
            measures: this.measures,
            mdxFunctions: this.mdxFunctions
        });

    },

    save: function (event) {
        event.preventDefault();
        var self = this;
        var measure_name = $(this.el).find('.measure_name').val();
        var measure_formula = $(this.el).find('.measureFormula').val();
        var measure_format = $(this.el).find('.measure_format').val();

        var alert_msg = "";
        if (typeof measure_name == "undefined" || !measure_name) {
            alert_msg += "You have to enter a name for the measure! ";
        }
        if (typeof measure_formula == "undefined" || !measure_formula || measure_formula === "") {
            alert_msg += "You have to enter a MDX formula for the calculated measure! ";
        }
        if (alert_msg !== "") {
            alert(alert_msg);
        } else {
            var m = { name: measure_name, formula: measure_formula, properties: {}, uniqueName: "[Measures]." + measure_name };
            if (measure_format) {
                m.properties.FORMAT_STRING = measure_format;
            }
            self.workspace.query.helper.addCalculatedMeasure(m);
            self.workspace.sync_query();
            this.close();
        }

        return false;
    },

    error: function () {
        $(this.el).find('dialog_body')
            .html("Could not add new folder");
    },

    addMathOperatorToCalculationField: function (event) {
        var mathOperator = ' ' + event.target.value + ' ';
        $(".measureFormula").val($(".measureFormula").val() + mathOperator);
    },

    addMeasureToCalculationField: function (event) {
        var measureName = this.$("#Measures option:selected").text();
        measureName = this.surroundWithSquareBrackets("Measures") + '.' + this.surroundWithSquareBrackets(measureName);
        $(".measureFormula").val($(".measureFormula").val() + measureName);
        this.resetSelectDropdown();
    },

    surroundWithSquareBrackets: function (text) {
        return '[' + text + ']';
    },

    resetSelectDropdown: function () {
        document.getElementById("Measures").selectedIndex = 0;
    }
});
<|endoftext|>


<commit_before>/*!
 * Copyright 2013 Apereo Foundation (AF) Licensed under the
 * Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

define(['jquery', 'oae.core', 'jquery.history'], function($, oae) {

    return function(uid, showSettings, widgetData) {

        // The widget container
        var $rootel = $('#' + uid);

        // Variables that will be used to keep track of the infinite scroll instances for following and followers
        var followingInfinityScroll = false;
        var followersInfinityScroll = false;

        /**
         * Initialize a new infinite scroll container that fetches the users the current user is following.
         * This will detect when a search is happening and will change the endpoint accordingly.
         */
        var getFollowing = function() {
            // Disable the previous infinite scroll
            if (followingInfinityScroll) {
                followingInfinityScroll.kill();
            }

            // Detect whether or not we need to do a search by checking if
            // the History.js state has a query parameter
            var query = History.getState().data.query;
            $('#network-search-query', $rootel).val(query);

            var url = '/api/following/' + widgetData.principalId + '/following';
            if (query) {
                url = '/api/search/following/' + widgetData.principalId;
            }

             // Set up the list actions
            var initialContent = null;
            if (widgetData.canManage && !query) {
                initialContent = oae.api.util.template().render($('#network-list-actions-template', $rootel));
            }

            // Set up the infinite scroll for the users followed by the current user
            followingInfinityScroll = $('#network-following .oae-list', $rootel).infiniteScroll(url, {
                'limit': 12,
                'q': query
            }, '#following-template', {
                initialContent: initialContent,
                'postProcessor': function(data) {
                    // Let the template know whether or not the current list
                    // is a main list or a search list, as different paging
                    // keys need to be provided for each
                    data.query = query;
                    data.canManage = widgetData.canManage;
                    return data;
                },
                'emptyListProcessor': function() {
                    oae.api.util.template().render($('#network-following-noresults-template', $rootel), {
                        'query': query
                    }, $('#network-following .oae-list', $rootel));
                }
            });
        };

        /**
         * Initialize a new infinite scroll container that fetches the current user's followers.
         * This will detect when a search is happening and will change the endpoint accordingly.
         */
        var getFollowers = function() {
            // Disable the previous infinite scroll
            if (followersInfinityScroll) {
                followersInfinityScroll.kill();
            }

            // Detect whether or not we need to do a search by checking if
            // the History.js state has a query parameter
            var query = History.getState().data.query;
            $('#network-search-query', $rootel).val(query);

            var url = '/api/following/' + widgetData.principalId + '/followers';
            if (query) {
                url = '/api/search/followers/' + widgetData.principalId;
            }

            // Set up the infinite scroll for the content library
            followersInfinityScroll = $('#network-followers .oae-list', $rootel).infiniteScroll(url, {
                'limit': 12,
                'q': query
            }, '#followers-template', {
                'postProcessor': function(data) {
                    // Let the template know whether or not the current list
                    // is a main list or a search list, as different paging
                    // keys need to be provided for each
                    data.query = query;

                    // Suppress links to user with private profiles
                    _.each(data.results, function(user) {
                       if (user.visibility === 'private') {
                           user.profilePath = false;
                       }
                    });
                    return data;
                },
                'emptyListProcessor': function() {
                    oae.api.util.template().render($('#network-followers-noresults-template', $rootel), {
                        'query': query
                    }, $('#network-followers .oae-list', $rootel));
                }
            });
        };

        /**
         * If the current user is an anonymous user, we disable the toggle that displays
         * the different list item actions. If the user is logged in, we render the list of
         * available action based on whether or not the user can manage the network.
         */
        var setUpListOptions = function() {
            if (oae.data.me.anon) {
                $('.oae-list-options-toggle', $rootel).prop('disabled', true);
            } else {
                oae.api.util.template().render($('#network-list-options-actions-template', $rootel), {
                    'widgetData': widgetData
                }, $('.oae-list-options-actions', $rootel));
            }
        };

        /**
         * Initiate a search with the search query entered by the user. An empty
         * search will just show the normal list.
         */
        var search = function() {
            var query = $('#network-search-query', $(this)).val();
            // Push the new query to a new History.js state. We make sure to take the
            // existing state data parameters with us and construct a new URL based on
            // the existing base URL, allowing for page refreshing and bookmarking.
            var newState = $.extend({}, History.getState().data, {
                'query': query
            });

            // We cannot rely on the "current" url as that can be different depending on the browser.
            // Most browsers will display `/me/network`, IE9 will be display `/me#network` however.
            // The cleanUrl in the History.js state will always be `/me/network`.
            var url = $.url(History.getState().cleanUrl).attr('path') + '?q=' + oae.api.util.security().encodeForURL(query);
            History.pushState(newState, $('title').text(), url);

            // Avoid that the search form is being submitted
            return false;
        };

        /**
         * Add the different event bindings
         */
        var addBinding = function() {
            // Set up search event
            $rootel.on('submit', '#network-search-form', search);

            // Listen to History.js state changes
            $(window).on('statechange', function() {
                // Reload the visible list
                if ($rootel.is(':visible')) {
                    if ($('.nav-tabs li.active a[data-type="followers"]').length) {
                        getFollowers();
                    } else {
                        getFollowing();
                    }
                }
            });

            // Disable/enable list option buttons per tab
            $('a[data-toggle="tab"]', $rootel).on('shown', function(ev) {
                if ($(ev.target).attr('data-type') === 'followers') {
                    getFollowers();
                    $('.oae-list-selectall', $rootel).hide();
                    $('.oae-trigger-unfollow', $rootel).hide();
                } else {
                    getFollowing();
                    $('.oae-list-selectall', $rootel).prop('checked', false);
                    $('.oae-list-selectall', $rootel).show();
                    $('.oae-trigger-unfollow', $rootel).show();
                }
            });

            // Refresh the list of followers and users I follow when users have been unfollowed
            $(document).on('oae.unfollow.done', getFollowing);
        };

        addBinding();
        getFollowing();
        setUpListOptions();

    };
});
<commit_msg>no need to explicitly clear profile path<commit_after>/*!
 * Copyright 2013 Apereo Foundation (AF) Licensed under the
 * Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

define(['jquery', 'oae.core', 'jquery.history'], function($, oae) {

    return function(uid, showSettings, widgetData) {

        // The widget container
        var $rootel = $('#' + uid);

        // Variables that will be used to keep track of the infinite scroll instances for following and followers
        var followingInfinityScroll = false;
        var followersInfinityScroll = false;

        /**
         * Initialize a new infinite scroll container that fetches the users the current user is following.
         * This will detect when a search is happening and will change the endpoint accordingly.
         */
        var getFollowing = function() {
            // Disable the previous infinite scroll
            if (followingInfinityScroll) {
                followingInfinityScroll.kill();
            }

            // Detect whether or not we need to do a search by checking if
            // the History.js state has a query parameter
            var query = History.getState().data.query;
            $('#network-search-query', $rootel).val(query);

            var url = '/api/following/' + widgetData.principalId + '/following';
            if (query) {
                url = '/api/search/following/' + widgetData.principalId;
            }

             // Set up the list actions
            var initialContent = null;
            if (widgetData.canManage && !query) {
                initialContent = oae.api.util.template().render($('#network-list-actions-template', $rootel));
            }

            // Set up the infinite scroll for the users followed by the current user
            followingInfinityScroll = $('#network-following .oae-list', $rootel).infiniteScroll(url, {
                'limit': 12,
                'q': query
            }, '#following-template', {
                initialContent: initialContent,
                'postProcessor': function(data) {
                    // Let the template know whether or not the current list
                    // is a main list or a search list, as different paging
                    // keys need to be provided for each
                    data.query = query;
                    data.canManage = widgetData.canManage;
                    return data;
                },
                'emptyListProcessor': function() {
                    oae.api.util.template().render($('#network-following-noresults-template', $rootel), {
                        'query': query
                    }, $('#network-following .oae-list', $rootel));
                }
            });
        };

        /**
         * Initialize a new infinite scroll container that fetches the current user's followers.
         * This will detect when a search is happening and will change the endpoint accordingly.
         */
        var getFollowers = function() {
            // Disable the previous infinite scroll
            if (followersInfinityScroll) {
                followersInfinityScroll.kill();
            }

            // Detect whether or not we need to do a search by checking if
            // the History.js state has a query parameter
            var query = History.getState().data.query;
            $('#network-search-query', $rootel).val(query);

            var url = '/api/following/' + widgetData.principalId + '/followers';
            if (query) {
                url = '/api/search/followers/' + widgetData.principalId;
            }

            // Set up the infinite scroll for the content library
            followersInfinityScroll = $('#network-followers .oae-list', $rootel).infiniteScroll(url, {
                'limit': 12,
                'q': query
            }, '#followers-template', {
                'postProcessor': function(data) {
                    // Let the template know whether or not the current list
                    // is a main list or a search list, as different paging
                    // keys need to be provided for each
                    data.query = query;
                    return data;
                },
                'emptyListProcessor': function() {
                    oae.api.util.template().render($('#network-followers-noresults-template', $rootel), {
                        'query': query
                    }, $('#network-followers .oae-list', $rootel));
                }
            });
        };

        /**
         * If the current user is an anonymous user, we disable the toggle that displays
         * the different list item actions. If the user is logged in, we render the list of
         * available action based on whether or not the user can manage the network.
         */
        var setUpListOptions = function() {
            if (oae.data.me.anon) {
                $('.oae-list-options-toggle', $rootel).prop('disabled', true);
            } else {
                oae.api.util.template().render($('#network-list-options-actions-template', $rootel), {
                    'widgetData': widgetData
                }, $('.oae-list-options-actions', $rootel));
            }
        };

        /**
         * Initiate a search with the search query entered by the user. An empty
         * search will just show the normal list.
         */
        var search = function() {
            var query = $('#network-search-query', $(this)).val();
            // Push the new query to a new History.js state. We make sure to take the
            // existing state data parameters with us and construct a new URL based on
            // the existing base URL, allowing for page refreshing and bookmarking.
            var newState = $.extend({}, History.getState().data, {
                'query': query
            });

            // We cannot rely on the "current" url as that can be different depending on the browser.
            // Most browsers will display `/me/network`, IE9 will be display `/me#network` however.
            // The cleanUrl in the History.js state will always be `/me/network`.
            var url = $.url(History.getState().cleanUrl).attr('path') + '?q=' + oae.api.util.security().encodeForURL(query);
            History.pushState(newState, $('title').text(), url);

            // Avoid that the search form is being submitted
            return false;
        };

        /**
         * Add the different event bindings
         */
        var addBinding = function() {
            // Set up search event
            $rootel.on('submit', '#network-search-form', search);

            // Listen to History.js state changes
            $(window).on('statechange', function() {
                // Reload the visible list
                if ($rootel.is(':visible')) {
                    if ($('.nav-tabs li.active a[data-type="followers"]').length) {
                        getFollowers();
                    } else {
                        getFollowing();
                    }
                }
            });

            // Disable/enable list option buttons per tab
            $('a[data-toggle="tab"]', $rootel).on('shown', function(ev) {
                if ($(ev.target).attr('data-type') === 'followers') {
                    getFollowers();
                    $('.oae-list-selectall', $rootel).hide();
                    $('.oae-trigger-unfollow', $rootel).hide();
                } else {
                    getFollowing();
                    $('.oae-list-selectall', $rootel).prop('checked', false);
                    $('.oae-list-selectall', $rootel).show();
                    $('.oae-trigger-unfollow', $rootel).show();
                }
            });

            // Refresh the list of followers and users I follow when users have been unfollowed
            $(document).on('oae.unfollow.done', getFollowing);
        };

        addBinding();
        getFollowing();
        setUpListOptions();

    };
});
<|endoftext|>


<commit_before>var addDirtyProps = require('../add-dirty-props');
var util = require('../util');
var noop = require('../no-op');
var passThrough = require('../pass-through');
var debounce = require('../debounce');

module.exports = function(_grid, name, lengthName, defaultSize) {
    var grid = _grid;

    var descriptors = [];
    var numFixed = 0;
    var numHeaders = 0;
    var makeDirtyClean = require('../dirty-clean');
    var dirtyClean = makeDirtyClean(grid);
    var builderDirtyClean = makeDirtyClean(grid);
    var selected = [];

    function setDescriptorsDirty(eventOptional) {
        var event = eventOptional || {};
        event.type = 'grid-' + name + '-change';
        grid.eventLoop.fire(event);
        dirtyClean.setDirty();
        builderDirtyClean.setDirty();
    }

    var fireSelectionChange = debounce(function() {
        grid.eventLoop.fire('grid-' + name + '-selection-change');
    }, 1);

    function updateDescriptorIndices() {
        var oldSelected = selected;
        selected = [];
        descriptors.forEach(function(descriptor, i) {
            descriptor.index = i;
            if (descriptor.selected) {
                selected.push(i);
            }
        });
        if (selected.length !== oldSelected.length) {
            fireSelectionChange();
        }
        selected.sort();
        oldSelected.sort();
        var change = oldSelected.some(function(idx, i) {
            return idx !== selected[i];
        });
        if (change) {
            fireSelectionChange();
        }
    }

    var api = {
        areBuildersDirty: builderDirtyClean.isDirty,
        isDirty: dirtyClean.isDirty,
        defaultSize: defaultSize,
        add: function(toAdd) {
            if (!toAdd) {
                return;
            }

            if (!util.isArray(toAdd)) {
                toAdd = [toAdd];
            }
            toAdd.forEach(function(descriptor) {
                if (descriptor.header) {
                    descriptors.splice(numHeaders, 0, descriptor);
                    numFixed++;
                    numHeaders++;
                } else {
                    // if the column is fixed and the last one added is fixed (we only allow fixed at the beginning for now)
                    if (descriptor.fixed) {
                        if (!descriptors.length || descriptors[descriptors.length - 1].fixed) {
                            numFixed++;
                        } else {
                            throw 'Cannot add a fixed column after an unfixed one';
                        }
                    }
                    descriptors.push(descriptor);
                }
            });
            updateDescriptorIndices();
            setDescriptorsDirty({
                action: 'add',
                descriptors: toAdd
            });
        },
        addHeaders: function(toAdd) {
            if (!toAdd) {
                return;
            }

            if (!util.isArray(toAdd)) {
                toAdd = [toAdd];
            }
            toAdd.forEach(function(header) {
                header.header = true;
            });
            api.add(toAdd);
        },
        header: function(index) {
            return descriptors[index];
        },
        get: function(index) {
            return descriptors[index];
        },
        length: function(includeHeaders) {
            var subtract = includeHeaders ? 0 : numHeaders;
            return descriptors.length - subtract;
        },
        remove: function(descriptor, dontUpdateIndex) {
            var index = descriptors.indexOf(descriptor);
            if (index !== -1) {
                descriptors.splice(index, 1);
                if (descriptor.header) {
                    numFixed--;
                    numHeaders--;
                } else if (descriptor.fixed) {
                    numFixed--;
                }
            }
            if (!dontUpdateIndex) {
                updateDescriptorIndices();
                setDescriptorsDirty({
                    action: 'remove',
                    descriptors: [descriptor]
                });
            }
        },
        clear: function(includeHeaders) {
            var removed = descriptors.slice(0).map(function(descriptor) {
                if (includeHeaders || !descriptor.header) {
                    api.remove(descriptor, true);
                    return descriptor;
                }
            });
            updateDescriptorIndices();
            setDescriptorsDirty({
                action: 'remove',
                descriptors: removed
            });
        },
        move: function(fromIndexes, target, after) {
            if (!util.isArray(fromIndexes)) {
                fromIndexes = [fromIndexes];
            }

            if (fromIndexes.length === 1) {
                // the single move case is easier and doesn't require the after hint
                var from = fromIndexes[0];
                descriptors.splice(target, 0, descriptors.splice(from, 1)[0]);
                setDescriptorsDirty({
                    action: 'move',
                    descriptors: [api.get(from), api.get(target)]
                });
            } else {
                var toValue = descriptors[target];
                var removed = fromIndexes.sort(function compareNumbers(a, b) {
                    return b - a;
                }).map(function(fromIndex) {
                    var removedDescriptors = descriptors.splice(fromIndex, 1);
                    return removedDescriptors[0];

                });
                removed.reverse();
                var spliceArgs = [descriptors.indexOf(toValue) + (after ? 1 : 0), 0].concat(removed);
                descriptors.splice.apply(descriptors, spliceArgs);
                updateDescriptorIndices();
                setDescriptorsDirty({
                    action: 'move',
                    descriptors: removed.concat(toValue)
                });
            }
        },
        numHeaders: function() {
            return numHeaders;
        },
        numFixed: function(excludeHeaders) {
            return numFixed - (excludeHeaders ? numHeaders : 0);
        },
        toVirtual: function(dataIndex) {
            return dataIndex + api.numHeaders();
        },
        toData: function(virtualIndex) {
            return virtualIndex - api.numHeaders();
        },

        select: function(indexes, dontFire) {
            if (!util.isArray(indexes)) {
                indexes = [indexes];
            }
            var changes = indexes.filter(function(idx) {
                var hasDescriptor = !!api[name](idx);
                if (!hasDescriptor) {
                    console.warn('Tried to select index that had no descriptor', idx);
                }
                return hasDescriptor;
            }).map(function(idx) {
                var descriptor = api[name](idx);
                if (!descriptor.selected) {
                    descriptor.selected = true;
                    selected.push(idx);
                    return idx;
                }
            });
            if (changes.length && !dontFire) {
                fireSelectionChange();
            }
        },
        deselect: function(indexes, dontFire) {
            if (!util.isArray(indexes)) {
                indexes = [indexes];
            }
            var changes = indexes.filter(function(idx) {
                var hasDescriptor = !!api[name](idx);
                if (!hasDescriptor) {
                    console.warn('Tried to deselect index that had no descriptor', idx);
                }
                return hasDescriptor;
            }).map(function(idx) {
                var descriptor = api[name](idx);
                if (descriptor.selected) {
                    descriptor.selected = false;
                    selected.splice(selected.indexOf(idx), 1);
                    return idx;
                }
            });
            if (changes.length && !dontFire) {
                fireSelectionChange();
            }
        },
        toggleSelect: function(index) {
            var descriptor = api[name](index);
            if (descriptor.selected) {
                api.deselect(index);
            } else {
                api.select(index);
            }
        },
        clearSelected: function() {
            // have to make a copy or we are iterating the same array we're removing from yikes.
            return api.deselect(api.getSelected().slice(0));
        },
        getSelected: function() {
            return selected;
        },
        allSelected: function() {
            return api.getSelected().length === api.length();
        },
        create: function(builder) {
            var descriptor = {};
            var fixed = false;
            Object.defineProperty(descriptor, 'fixed', {
                enumerable: true,
                get: function() {
                    return descriptor.header || fixed;
                },
                set: function(_fixed) {
                    fixed = _fixed;
                }
            });
            var expanded = false;
            var expandedClass;
            Object.defineProperty(descriptor, 'expanded', {
                get: function() {
                    return expanded;
                },
                set: function(exp) {
                    if (!descriptor.children) {
                        return;
                    }
                    expanded = exp;
                    // we never look for changes to the children, if you need to change it, remove and add the row again
                    if (expanded) {
                        var spliceArgs = [descriptor.index + 1, 0].concat(descriptor.children)
                        descriptors.splice.apply(descriptors, spliceArgs);
                        updateDescriptorIndices();
                        setDescriptorsDirty({
                            action: 'add',
                            descriptors: descriptor.children
                        });
                        var top = name === 'row' ? descriptor.index : 0;
                        var left = name === 'col' ? descriptor.index : 0;
                        var height = name === 'row' ? 1 : Infinity;
                        var width = name === 'col' ? 1 : Infinity;
                        expandedClass = grid.cellClasses.create(top, left, 'grid-expanded', height, width, 'virtual');
                        grid.cellClasses.add(expandedClass);

                    } else {
                        descriptors.splice(descriptor.index + 1, descriptor.children.length);
                        updateDescriptorIndices();
                        setDescriptorsDirty({
                            action: 'remove',
                            descriptors: [descriptor.children]
                        });
                        if (expandedClass) {
                            grid.cellClasses.remove(expandedClass);
                        }
                    }
                }
            });

            addDirtyProps(descriptor, ['builder'], [builderDirtyClean]);
            descriptor.builder = builder;

            return addDirtyProps(descriptor, [{
                name: lengthName,
                onDirty: function() {
                    setDescriptorsDirty({
                        action: 'size',
                        descriptors: [descriptor]
                    });
                }
            }, {
                name: 'hidden',
                onDirty: function() {
                    setDescriptorsDirty({
                        action: 'hide',
                        descriptors: [descriptor]
                    });
                }
            }], [dirtyClean]);
        },
        createBuilder: function(render, update) {
            return {
                render: render || noop,
                update: update || passThrough
            };
        }

    };

    // basically height or width
    api[lengthName] = function(index) {
        var descriptor = descriptors[index];
        if (!descriptor) {
            return NaN;
        }

        if (descriptor.hidden) {
            return 0;
        }

        return descriptor[lengthName] || api.defaultSize;
    };

    // row or col get
    api[name] = function(index) {
        return descriptors[index + numHeaders];
    };

    return api;
};<commit_msg>make clearing way faster<commit_after>var addDirtyProps = require('../add-dirty-props');
var util = require('../util');
var noop = require('../no-op');
var passThrough = require('../pass-through');
var debounce = require('../debounce');

module.exports = function(_grid, name, lengthName, defaultSize) {
    var grid = _grid;

    var descriptors = [];
    var numFixed = 0;
    var numHeaders = 0;
    var makeDirtyClean = require('../dirty-clean');
    var dirtyClean = makeDirtyClean(grid);
    var builderDirtyClean = makeDirtyClean(grid);
    var selected = [];

    function setDescriptorsDirty(eventOptional) {
        var event = eventOptional || {};
        event.type = 'grid-' + name + '-change';
        grid.eventLoop.fire(event);
        dirtyClean.setDirty();
        builderDirtyClean.setDirty();
    }

    var fireSelectionChange = debounce(function() {
        grid.eventLoop.fire('grid-' + name + '-selection-change');
    }, 1);

    function updateDescriptorIndices() {
        var oldSelected = selected;
        selected = [];
        descriptors.forEach(function(descriptor, i) {
            descriptor.index = i;
            if (descriptor.selected) {
                selected.push(i);
            }
        });
        if (selected.length !== oldSelected.length) {
            fireSelectionChange();
        }
        selected.sort();
        oldSelected.sort();
        var change = oldSelected.some(function(idx, i) {
            return idx !== selected[i];
        });
        if (change) {
            fireSelectionChange();
        }
    }

    var api = {
        areBuildersDirty: builderDirtyClean.isDirty,
        isDirty: dirtyClean.isDirty,
        defaultSize: defaultSize,
        add: function(toAdd) {
            if (!toAdd) {
                return;
            }

            if (!util.isArray(toAdd)) {
                toAdd = [toAdd];
            }
            toAdd.forEach(function(descriptor) {
                if (descriptor.header) {
                    descriptors.splice(numHeaders, 0, descriptor);
                    numFixed++;
                    numHeaders++;
                } else {
                    // if the column is fixed and the last one added is fixed (we only allow fixed at the beginning for now)
                    if (descriptor.fixed) {
                        if (!descriptors.length || descriptors[descriptors.length - 1].fixed) {
                            numFixed++;
                        } else {
                            throw 'Cannot add a fixed column after an unfixed one';
                        }
                    }
                    descriptors.push(descriptor);
                }
            });
            updateDescriptorIndices();
            setDescriptorsDirty({
                action: 'add',
                descriptors: toAdd
            });
        },
        addHeaders: function(toAdd) {
            if (!toAdd) {
                return;
            }

            if (!util.isArray(toAdd)) {
                toAdd = [toAdd];
            }
            toAdd.forEach(function(header) {
                header.header = true;
            });
            api.add(toAdd);
        },
        header: function(index) {
            return descriptors[index];
        },
        get: function(index) {
            return descriptors[index];
        },
        length: function(includeHeaders) {
            var subtract = includeHeaders ? 0 : numHeaders;
            return descriptors.length - subtract;
        },
        remove: function(descriptor, dontUpdateIndex) {
            var index = descriptors.indexOf(descriptor);
            if (index !== -1) {
                descriptors.splice(index, 1);
                if (descriptor.header) {
                    numFixed--;
                    numHeaders--;
                } else if (descriptor.fixed) {
                    numFixed--;
                }
            }
            if (!dontUpdateIndex) {
                updateDescriptorIndices();
                setDescriptorsDirty({
                    action: 'remove',
                    descriptors: [descriptor]
                });
            }
        },
        clear: function(includeHeaders) {
            var removed;
            if (includeHeaders) {
                removed = descriptors;
                descriptors = [];
                numFixed = 0;
                numHeaders = 0;
            } else {
                removed = descriptors.slice(numHeaders);
                descriptors = descriptors.slice(0, numHeaders);
                numFixed = numHeaders;
            }
            updateDescriptorIndices();
            if (removed && removed.length) {
                setDescriptorsDirty({
                    action: 'remove',
                    descriptors: removed
                });
            }
        },
        move: function(fromIndexes, target, after) {
            if (!util.isArray(fromIndexes)) {
                fromIndexes = [fromIndexes];
            }

            if (fromIndexes.length === 1) {
                // the single move case is easier and doesn't require the after hint
                var from = fromIndexes[0];
                descriptors.splice(target, 0, descriptors.splice(from, 1)[0]);
                setDescriptorsDirty({
                    action: 'move',
                    descriptors: [api.get(from), api.get(target)]
                });
            } else {
                var toValue = descriptors[target];
                var removed = fromIndexes.sort(function compareNumbers(a, b) {
                    return b - a;
                }).map(function(fromIndex) {
                    var removedDescriptors = descriptors.splice(fromIndex, 1);
                    return removedDescriptors[0];

                });
                removed.reverse();
                var spliceArgs = [descriptors.indexOf(toValue) + (after ? 1 : 0), 0].concat(removed);
                descriptors.splice.apply(descriptors, spliceArgs);
                updateDescriptorIndices();
                setDescriptorsDirty({
                    action: 'move',
                    descriptors: removed.concat(toValue)
                });
            }
        },
        numHeaders: function() {
            return numHeaders;
        },
        numFixed: function(excludeHeaders) {
            return numFixed - (excludeHeaders ? numHeaders : 0);
        },
        toVirtual: function(dataIndex) {
            return dataIndex + api.numHeaders();
        },
        toData: function(virtualIndex) {
            return virtualIndex - api.numHeaders();
        },

        select: function(indexes, dontFire) {
            if (!util.isArray(indexes)) {
                indexes = [indexes];
            }
            var changes = indexes.filter(function(idx) {
                var hasDescriptor = !!api[name](idx);
                if (!hasDescriptor) {
                    console.warn('Tried to select index that had no descriptor', idx);
                }
                return hasDescriptor;
            }).map(function(idx) {
                var descriptor = api[name](idx);
                if (!descriptor.selected) {
                    descriptor.selected = true;
                    selected.push(idx);
                    return idx;
                }
            });
            if (changes.length && !dontFire) {
                fireSelectionChange();
            }
        },
        deselect: function(indexes, dontFire) {
            if (!util.isArray(indexes)) {
                indexes = [indexes];
            }
            var changes = indexes.filter(function(idx) {
                var hasDescriptor = !!api[name](idx);
                if (!hasDescriptor) {
                    console.warn('Tried to deselect index that had no descriptor', idx);
                }
                return hasDescriptor;
            }).map(function(idx) {
                var descriptor = api[name](idx);
                if (descriptor.selected) {
                    descriptor.selected = false;
                    selected.splice(selected.indexOf(idx), 1);
                    return idx;
                }
            });
            if (changes.length && !dontFire) {
                fireSelectionChange();
            }
        },
        toggleSelect: function(index) {
            var descriptor = api[name](index);
            if (descriptor.selected) {
                api.deselect(index);
            } else {
                api.select(index);
            }
        },
        clearSelected: function() {
            // have to make a copy or we are iterating the same array we're removing from yikes.
            return api.deselect(api.getSelected().slice(0));
        },
        getSelected: function() {
            return selected;
        },
        allSelected: function() {
            return api.getSelected().length === api.length();
        },
        create: function(builder) {
            var descriptor = {};
            var fixed = false;
            Object.defineProperty(descriptor, 'fixed', {
                enumerable: true,
                get: function() {
                    return descriptor.header || fixed;
                },
                set: function(_fixed) {
                    fixed = _fixed;
                }
            });
            var expanded = false;
            var expandedClass;
            Object.defineProperty(descriptor, 'expanded', {
                get: function() {
                    return expanded;
                },
                set: function(exp) {
                    if (!descriptor.children) {
                        return;
                    }
                    expanded = exp;
                    // we never look for changes to the children, if you need to change it, remove and add the row again
                    if (expanded) {
                        var spliceArgs = [descriptor.index + 1, 0].concat(descriptor.children)
                        descriptors.splice.apply(descriptors, spliceArgs);
                        updateDescriptorIndices();
                        setDescriptorsDirty({
                            action: 'add',
                            descriptors: descriptor.children
                        });
                        var top = name === 'row' ? descriptor.index : 0;
                        var left = name === 'col' ? descriptor.index : 0;
                        var height = name === 'row' ? 1 : Infinity;
                        var width = name === 'col' ? 1 : Infinity;
                        expandedClass = grid.cellClasses.create(top, left, 'grid-expanded', height, width, 'virtual');
                        grid.cellClasses.add(expandedClass);

                    } else {
                        descriptors.splice(descriptor.index + 1, descriptor.children.length);
                        updateDescriptorIndices();
                        setDescriptorsDirty({
                            action: 'remove',
                            descriptors: [descriptor.children]
                        });
                        if (expandedClass) {
                            grid.cellClasses.remove(expandedClass);
                        }
                    }
                }
            });

            addDirtyProps(descriptor, ['builder'], [builderDirtyClean]);
            descriptor.builder = builder;

            return addDirtyProps(descriptor, [{
                name: lengthName,
                onDirty: function() {
                    setDescriptorsDirty({
                        action: 'size',
                        descriptors: [descriptor]
                    });
                }
            }, {
                name: 'hidden',
                onDirty: function() {
                    setDescriptorsDirty({
                        action: 'hide',
                        descriptors: [descriptor]
                    });
                }
            }], [dirtyClean]);
        },
        createBuilder: function(render, update) {
            return {
                render: render || noop,
                update: update || passThrough
            };
        }

    };

    // basically height or width
    api[lengthName] = function(index) {
        var descriptor = descriptors[index];
        if (!descriptor) {
            return NaN;
        }

        if (descriptor.hidden) {
            return 0;
        }

        return descriptor[lengthName] || api.defaultSize;
    };

    // row or col get
    api[name] = function(index) {
        return descriptors[index + numHeaders];
    };

    return api;
};<|endoftext|>


<commit_before>/*
 * Route controller.
 */

/*
 * Module dependencies.
 */
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var express = require('express');
var async = require('async');

/**
 * Main route controller class.
 *
 * @param {Application} application Application.
 * @param {Object} settings Application settings object.
 * @class RouteController
 */
var RouteController = module.exports = function(application, settings) {
  this.application = application;
  this.settings = settings;

  var self = this;
  var app = this.application.application;

  app.all(self.settings.path, function(request, response) {
    self.handle(request, response);
  });
};

/**
 * Handle a request.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object
 */
RouteController.prototype.handle = function(request, response) {
  var self = this;
  var settings = this.settings;

  this.access(request, response, function(err, allow) {
    if (err) {
      RouteController.error.call(self, request, response, err);
    }

    if (allow) {
      // A route can have either a content or callback property.
      if (settings.content) {
        RouteController.respond.call(self, request, response, settings.content);
      }
      else if (settings.callback) {
        settings.callback(request, response, function(err, content, code) {
          if (err) {
            RouteController.error.call(self, request, response, err);
          }

          if (content) {
            RouteController.respond.call(self, request, response, content, code);
          }
          else {
            // If there's no content, return 404 error.
            RouteController.notFound.call(self, request, response);
          }
        });
      }
    }
    else {
      // Access denied.
      RouteController.forbidden.call(self, request, response);
    }
  });
};

/**
 * Access check.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 * @param {Function} callaback Function called with the access check results.
 */
RouteController.prototype.access = function(request, response, callback) {
  var settings = this.settings;

  // If this is an object, do access check and other mandatory stuff.
  if (settings.access) {
    if (typeof settings.access === 'boolean') {
      // Access check is a string/permission key.
      return callback(null, settings.access);
    }
    else if (typeof settings.access === 'string') {
      return this.application.access(request, settings.access, callback);
    }
    else if (typeof settings.access === 'function') {
      // Access check is a callback.
      return settings.access(request, response, callback);
    }
  }

  // Default to false. Deny access.
  return callback(null, false);
};

/**
 * Respond to a request.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 * @param {Object|String} content Content to send.
 * @param {Number} [code] HTTP status code.
 */
RouteController.respond = function(request, response, content, code) {

  // Set defaults.
  code = typeof code != 'undefined' ? code : 200;
  var payload = {
    status: {
      code: code
    }
  };

  if (content) {
    payload.data = content;
  }

  // Run responseAlter() hook on all extensions.
  this.application.invoke('responseAlter', payload, request, response, function() {
    response.send(payload.status.code, payload);
  });
};

/**
 * Respond to a request with a "server error".
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.error = function(request, response, error) {
  RouteController.respond.call(this, request, response, {
    title: 'Server error',
    description: "The server couldn't process the request.",
    error: error.toString()
  }, 500);
};

/**
 * Respond to a request with a "page not found" error.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.notFound = function(request, response) {
  RouteController.respond.call(this, request, response, {
    title: 'Page not found',
    description: "The page you're looking for wasn't found."
  }, 404);
};

/**
 * Respond to a request with a "forbidden" error.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.forbidden = function(request, response) {
  RouteController.respond.call(this, request, response, {
    title: 'Forbidden',
    description: "You don't have permission to access this page."
  }, 403);
};
<commit_msg>Minor change to roll back code to what it looked before.<commit_after>/*
 * Route controller.
 */

/*
 * Module dependencies.
 */
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var express = require('express');
var async = require('async');

/**
 * Main route controller class.
 *
 * @param {Application} application Application.
 * @param {Object} settings Application settings object.
 * @class RouteController
 */
var RouteController = module.exports = function(application, settings) {
  this.application = application;
  this.settings = settings;

  var self = this;
  var app = this.application.application;

  app.all(self.settings.path, function(request, response) {
    self.handle(request, response);
  });
};

/**
 * Handle a request.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object
 */
RouteController.prototype.handle = function(request, response) {
  var self = this;
  var settings = this.settings;

  this.access(request, response, function(err, allow) {
    if (err) {
      RouteController.error.call(self, request, response, err);
    }

    if (allow) {
      // A route can have either a content or callback property.
      if (settings.content) {
        RouteController.respond.call(self, request, response, settings.content);
      }
      else if (settings.callback) {
        settings.callback(request, response, function(err, content, code) {
          if (err) {
            RouteController.error.call(self, request, response, err);
          }

          if (content) {
            RouteController.respond.call(self, request, response, content, code);
          }
          else {
            // If there's no content, return 404 error.
            RouteController.notFound.call(self, request, response);
          }
        });
      }
    }
    else {
      // Access denied.
      RouteController.forbidden.call(self, request, response);
    }
  });
};

/**
 * Access check.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 * @param {Function} callaback Function called with the access check results.
 */
RouteController.prototype.access = function(request, response, callback) {
  var settings = this.settings;

  // If this is an object, do access check and other mandatory stuff.
  if (settings.access) {
    if (typeof settings.access === 'boolean') {
      // Access check is a string/permission key.
      return callback(null, settings.access);
    }
    else if (typeof settings.access === 'string') {
      return this.application.access(request, settings.access, callback);
    }
    else if (typeof settings.access === 'function') {
      // Access check is a callback.
      return settings.access(request, response, callback);
    }
  }

  // Default to false. Deny access.
  return callback(null, false);
};

/**
 * Respond to a request.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 * @param {Object|String} content Content to send.
 * @param {Number} [code] HTTP status code.
 */
RouteController.respond = function(request, response, content, code) {
  // Default to 200 (success).
  var code = code || 200;
  var payload = {
    status: {
      code: code
    }
  };

  if (content) {
    payload.data = content;
  }

  // Run responseAlter() hook on all extensions.
  this.application.invoke('responseAlter', payload, request, response, function() {
    response.send(payload.status.code, payload);
  });
};

/**
 * Respond to a request with a "server error".
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.error = function(request, response, error) {
  RouteController.respond.call(this, request, response, {
    title: 'Server error',
    description: "The server couldn't process the request.",
    error: error.toString()
  }, 500);
};

/**
 * Respond to a request with a "page not found" error.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.notFound = function(request, response) {
  RouteController.respond.call(this, request, response, {
    title: 'Page not found',
    description: "The page you're looking for wasn't found."
  }, 404);
};

/**
 * Respond to a request with a "forbidden" error.
 *
 * @param {Request} request Request object.
 * @param {Response} response Response object.
 */
RouteController.forbidden = function(request, response) {
  RouteController.respond.call(this, request, response, {
    title: 'Forbidden',
    description: "You don't have permission to access this page."
  }, 403);
};
<|endoftext|>