mirror of
https://github.com/ENSL/ensl_gathers.git
synced 2024-11-22 12:41:11 +00:00
more migration stuff.............
This commit is contained in:
parent
1720f0a513
commit
fce8039e3e
24 changed files with 26318 additions and 10271 deletions
18
README.md
18
README.md
|
@ -16,16 +16,26 @@ That's it
|
|||
|
||||
## Requirements
|
||||
|
||||
- node.js 0.12
|
||||
- node.js > 4.0
|
||||
|
||||
- MongoDB
|
||||
|
||||
## Run
|
||||
## Run in development
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm install # Install deps
|
||||
|
||||
npm start
|
||||
npm run watch # Compile and watch frontend assets
|
||||
|
||||
RANDOM_USER=true npm run dev # Run dev server, loading yourself as a random user
|
||||
```
|
||||
|
||||
## Run in production
|
||||
|
||||
```bash
|
||||
npm install # Install deps
|
||||
|
||||
npm start_production # Compile assets and run in production
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
const React = require("react");
|
||||
const ReactDOM = require("react-dom");
|
||||
const App = require("javascripts/components/main");
|
||||
|
||||
const App = require("components/main");
|
||||
|
||||
module.exports = mount => { ReactDOM.render(App, mount) };
|
||||
module.exports = function (mount) {
|
||||
ReactDOM.render(<App />, mount);
|
||||
};
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
const $ = require("jquery");
|
||||
const React = require("react");
|
||||
|
||||
const Events = React.createClass({
|
||||
const Events = exports.Events = React.createClass({
|
||||
propTypes: {
|
||||
events: React.PropTypes.array.isRequired
|
||||
},
|
||||
|
@ -16,16 +14,17 @@ const Events = React.createClass({
|
|||
events = this.props.events.map(event => {
|
||||
return `${this.getTime(event.createdAt)} ${event.description}`;
|
||||
}).join("\n");
|
||||
return (
|
||||
<pre className="events-panel">
|
||||
{events}
|
||||
</pre>
|
||||
);
|
||||
} else {
|
||||
events = <tr><td>Listening for new events...</td></tr>
|
||||
return (
|
||||
<pre className="events-panel">
|
||||
Listening for new events...
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<pre className="events-panel">
|
||||
{events}
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Events;
|
|
@ -1,15 +1,22 @@
|
|||
import {AssumeUserIdButton} from "javascripts/components/user";
|
||||
|
||||
const React = require("react");
|
||||
const helper = require("javascripts/helper");
|
||||
const enslUrl = helper.enslUrl;
|
||||
const rankVotes = helper.rankeVotes;
|
||||
const hiveUrl = helper.hiveUrl;
|
||||
|
||||
var SelectPlayerButton = React.createClass({
|
||||
const SelectPlayerButton = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
gatherer: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
selectPlayer(e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:select", {
|
||||
this.props.socket.emit("gather:select", {
|
||||
player: parseInt(e.target.value, 10)
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
|
@ -35,16 +42,16 @@ var SelectPlayerButton = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var GathererList = React.createClass({
|
||||
const GathererList = React.createClass({
|
||||
memberList() {
|
||||
var self = this;
|
||||
const self = this;
|
||||
return this.props.gather.gatherers
|
||||
.filter(gatherer => gatherer.team === self.props.team)
|
||||
.sort(gatherer => { return gatherer.leader ? 1 : -1 });
|
||||
},
|
||||
|
||||
render() {
|
||||
var extractGatherer = gatherer => {
|
||||
const extractGatherer = gatherer => {
|
||||
let image;
|
||||
if (gatherer.leader) {
|
||||
image = <i className="fa fa-star add-right"></i>;
|
||||
|
@ -59,8 +66,8 @@ var GathererList = React.createClass({
|
|||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
var members = this.memberList()
|
||||
};
|
||||
const members = this.memberList()
|
||||
.map(extractGatherer);
|
||||
return (
|
||||
<table className="table">
|
||||
|
@ -72,7 +79,7 @@ var GathererList = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var GatherTeams = React.createClass({
|
||||
const GatherTeams = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<div className="row add-top">
|
||||
|
@ -97,18 +104,18 @@ var GatherTeams = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var ElectionProgressBar = React.createClass({
|
||||
const ElectionProgressBar = React.createClass({
|
||||
componentDidMount() {
|
||||
var self = this;
|
||||
const self = this;
|
||||
this.timer = setInterval(() => {
|
||||
self.forceUpdate();
|
||||
}, 900);
|
||||
},
|
||||
|
||||
progress() {
|
||||
var interval = this.props.gather.election.interval;
|
||||
var startTime = (new Date(this.props.gather.election.startTime)).getTime();
|
||||
var msTranspired = Math.floor((new Date()).getTime() - startTime);
|
||||
const interval = this.props.gather.election.interval;
|
||||
const startTime = (new Date(this.props.gather.election.startTime)).getTime();
|
||||
const msTranspired = Math.floor((new Date()).getTime() - startTime);
|
||||
|
||||
return {
|
||||
num: msTranspired,
|
||||
|
@ -126,13 +133,13 @@ var ElectionProgressBar = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var ProgressBar = React.createClass({
|
||||
const ProgressBar = React.createClass({
|
||||
render() {
|
||||
let progress = this.props.progress;
|
||||
var style = {
|
||||
const progress = this.props.progress;
|
||||
const style = {
|
||||
width: Math.round((progress.num / progress.den * 100)) + "%"
|
||||
};
|
||||
var barMessage = progress.barMessage || "";
|
||||
const barMessage = progress.barMessage || "";
|
||||
return (
|
||||
<div className="progress">
|
||||
<div className="progress-bar progress-bar-striped active"
|
||||
|
@ -147,7 +154,7 @@ var ProgressBar = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var GatherProgress = React.createClass({
|
||||
const GatherProgress = React.createClass({
|
||||
stateDescription() {
|
||||
switch(this.props.gather.state) {
|
||||
case "gathering":
|
||||
|
@ -164,10 +171,10 @@ var GatherProgress = React.createClass({
|
|||
},
|
||||
|
||||
gatheringProgress() {
|
||||
var num = this.props.gather.gatherers.length;
|
||||
var den = 12;
|
||||
var remaining = den - num;
|
||||
var message = (remaining === 1) ?
|
||||
const num = this.props.gather.gatherers.length;
|
||||
const den = 12;
|
||||
const remaining = den - num;
|
||||
const message = (remaining === 1) ?
|
||||
"Waiting for last player" : `Waiting for ${remaining} more players`;
|
||||
return {
|
||||
num: num,
|
||||
|
@ -177,11 +184,11 @@ var GatherProgress = React.createClass({
|
|||
},
|
||||
|
||||
electionProgress() {
|
||||
var num = this.props.gather.gatherers.reduce((acc, gatherer) => {
|
||||
const num = this.props.gather.gatherers.reduce((acc, gatherer) => {
|
||||
if (gatherer.leaderVote) acc++;
|
||||
return acc;
|
||||
}, 0);
|
||||
var den = 12;
|
||||
const den = 12;
|
||||
return {
|
||||
num: num,
|
||||
den: den,
|
||||
|
@ -190,11 +197,11 @@ var GatherProgress = React.createClass({
|
|||
},
|
||||
|
||||
selectionProgress() {
|
||||
var num = this.props.gather.gatherers.reduce((acc, gatherer) => {
|
||||
const num = this.props.gather.gatherers.reduce((acc, gatherer) => {
|
||||
if (gatherer.team !== "lobby") acc++;
|
||||
return acc;
|
||||
}, 0);
|
||||
var den = 12;
|
||||
const den = 12;
|
||||
|
||||
return {
|
||||
num: num,
|
||||
|
@ -205,8 +212,8 @@ var GatherProgress = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
var progress, progressBar;
|
||||
var gatherState = this.props.gather.state;
|
||||
let progress, progressBar;
|
||||
const gatherState = this.props.gather.state;
|
||||
if (gatherState === 'gathering' && this.props.gather.gatherers.length) {
|
||||
progress = this.gatheringProgress();
|
||||
progressBar = (<ProgressBar progress={progress} />);
|
||||
|
@ -229,91 +236,16 @@ var GatherProgress = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
let teamspeakDefaults = {
|
||||
url: "ts3server://ensl.org/",
|
||||
password: "ns2gather",
|
||||
alien: {
|
||||
channel: "NS2 Gather/Gather #1/Alien",
|
||||
password: "ns2gather"
|
||||
},
|
||||
marine: {
|
||||
channel: "NS2 Gather/Gather #1/Marine",
|
||||
password: "ns2gather"
|
||||
}
|
||||
};
|
||||
|
||||
var TeamSpeakButton = React.createClass({
|
||||
getDefaultProps() {
|
||||
return teamspeakDefaults
|
||||
},
|
||||
marineUrl() {
|
||||
return this.teamSpeakUrl(this.props.marine);
|
||||
},
|
||||
alienUrl() {
|
||||
return this.teamSpeakUrl(this.props.alien);
|
||||
},
|
||||
teamSpeakUrl(conn) {
|
||||
let params = `channel=${encodeURIComponent(conn.channel)}&
|
||||
channelpassword=${encodeURIComponent(conn.password)}`;
|
||||
return (`${this.props.url}?${params}`);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<ul className="nav navbar-top-links navbar-right">
|
||||
<li className="dropdown">
|
||||
<a className="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Teamspeak <i className="fa fa-caret-down"></i>
|
||||
</a>
|
||||
<ul className="dropdown-menu">
|
||||
<li><a href={this.props.url}>Join Teamspeak Lobby</a></li>
|
||||
<li><a href={this.marineUrl()}>Join Marine Teamspeak</a></li>
|
||||
<li><a href={this.alienUrl()}>Join Alien Teamspeak</a></li>
|
||||
<li role="separator" className="divider"></li>
|
||||
<li><a href="#" data-toggle="modal" data-target="#teamspeakmodal">Teamspeak Details</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var TeamSpeakModal = React.createClass({
|
||||
getDefaultProps() {
|
||||
return teamspeakDefaults;
|
||||
const JoinGatherButton = React.createClass({
|
||||
propTypes: {
|
||||
thisGatherer: React.PropTypes.object,
|
||||
user: React.PropTypes.object.isRequired,
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
gather: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
return <div className="modal fade text-left" id="teamspeakmodal">
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<button type="button"
|
||||
className="close"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 className="modal-title">Teamspeak Server Information</h4>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<dl className="dl-horizontal">
|
||||
<dt>Server</dt>
|
||||
<dd>{this.props.url}</dd>
|
||||
<dt>Password</dt>
|
||||
<dd>{this.props.password}</dd>
|
||||
<dt>Marine Channel</dt>
|
||||
<dd>{this.props.marine.channel}</dd>
|
||||
<dt>Alien Channel</dt>
|
||||
<dd>{this.props.alien.channel}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
});
|
||||
|
||||
var JoinGatherButton = React.createClass({
|
||||
componentDidMount() {
|
||||
var self = this;
|
||||
const self = this;
|
||||
this.timer = setInterval(() => {
|
||||
self.forceUpdate();
|
||||
}, 30000);
|
||||
|
@ -325,12 +257,12 @@ var JoinGatherButton = React.createClass({
|
|||
|
||||
joinGather(e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:join");
|
||||
this.props.socket.emit("gather:join");
|
||||
},
|
||||
|
||||
leaveGather(e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:leave");
|
||||
this.props.socket.emit("gather:leave");
|
||||
},
|
||||
|
||||
cooldownTime() {
|
||||
|
@ -364,7 +296,11 @@ var JoinGatherButton = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var CooloffButton = React.createClass({
|
||||
const CooloffButton = React.createClass({
|
||||
propTypes: {
|
||||
timeRemaining: React.PropTypes.number.isRequired
|
||||
},
|
||||
|
||||
timeRemaining() {
|
||||
return `${Math.floor(this.props.timeRemaining / 60000) + 1} minutes remaining`;
|
||||
},
|
||||
|
@ -378,10 +314,16 @@ var CooloffButton = React.createClass({
|
|||
}
|
||||
})
|
||||
|
||||
var GatherActions = React.createClass({
|
||||
const GatherActions = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
gather: React.PropTypes.object.isRequired,
|
||||
thisGatherer: React.PropTypes.object
|
||||
},
|
||||
|
||||
voteRegather(e) {
|
||||
e.preventDefault(e);
|
||||
socket.emit("gather:vote", {
|
||||
this.props.socket.emit("gather:vote", {
|
||||
regather: (e.target.value === "true")
|
||||
});
|
||||
},
|
||||
|
@ -397,9 +339,10 @@ var GatherActions = React.createClass({
|
|||
|
||||
render() {
|
||||
let regatherButton;
|
||||
let user = this.props.user;
|
||||
let gather = this.props.gather;
|
||||
let thisGatherer = this.props.thisGatherer;
|
||||
const user = this.props.user;
|
||||
const gather = this.props.gather;
|
||||
const socket = this.props.socket;
|
||||
const thisGatherer = this.props.thisGatherer;
|
||||
if (thisGatherer) {
|
||||
let regatherVotes = this.regatherVotes();
|
||||
if (thisGatherer.regatherVote) {
|
||||
|
@ -424,7 +367,7 @@ var GatherActions = React.createClass({
|
|||
</li>
|
||||
<li>
|
||||
<JoinGatherButton gather={gather} thisGatherer={thisGatherer}
|
||||
user={user} />
|
||||
user={user} socket={socket} />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -433,9 +376,15 @@ var GatherActions = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var VoteButton = React.createClass({
|
||||
const VoteButton = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
candidate: React.PropTypes.object.isRequired,
|
||||
thisGatherer: React.PropTypes.object
|
||||
},
|
||||
|
||||
cancelVote(e) {
|
||||
socket.emit("gather:vote", {
|
||||
this.props.socket.emit("gather:vote", {
|
||||
leader: {
|
||||
candidate: null
|
||||
}
|
||||
|
@ -444,7 +393,7 @@ var VoteButton = React.createClass({
|
|||
|
||||
vote(e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:vote", {
|
||||
this.props.socket.emit("gather:vote", {
|
||||
leader: {
|
||||
candidate: parseInt(e.target.value, 10)
|
||||
}
|
||||
|
@ -480,11 +429,18 @@ var VoteButton = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var ServerVoting = React.createClass({
|
||||
const ServerVoting = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
gather: React.PropTypes.object.isRequired,
|
||||
thisGatherer: React.PropTypes.object,
|
||||
servers: React.PropTypes.array.isRequired,
|
||||
},
|
||||
|
||||
voteHandler(serverId) {
|
||||
return function (e) {
|
||||
return e => {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:vote", {
|
||||
this.props.socket.emit("gather:vote", {
|
||||
server: {
|
||||
id: serverId
|
||||
}
|
||||
|
@ -503,8 +459,8 @@ var ServerVoting = React.createClass({
|
|||
let self = this;
|
||||
let thisGatherer = self.props.thisGatherer;
|
||||
let servers = self.props.servers.sort((a, b) => {
|
||||
var aVotes = self.votesForServer(a);
|
||||
var bVotes = self.votesForServer(b);
|
||||
const aVotes = self.votesForServer(a);
|
||||
const bVotes = self.votesForServer(b);
|
||||
return bVotes - aVotes;
|
||||
}).map(server => {
|
||||
let votes = self.votesForServer(server);
|
||||
|
@ -537,11 +493,18 @@ var ServerVoting = React.createClass({
|
|||
}
|
||||
})
|
||||
|
||||
var MapVoting = React.createClass({
|
||||
const MapVoting = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
gather: React.PropTypes.object.isRequired,
|
||||
thisGatherer: React.PropTypes.object,
|
||||
maps: React.PropTypes.array.isRequired,
|
||||
},
|
||||
|
||||
voteHandler(mapId) {
|
||||
return function (e) {
|
||||
return e => {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:vote", {
|
||||
this.props.socket.emit("gather:vote", {
|
||||
map: {
|
||||
id: mapId
|
||||
}
|
||||
|
@ -557,11 +520,11 @@ var MapVoting = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
var self = this;
|
||||
const self = this;
|
||||
let thisGatherer = self.props.thisGatherer
|
||||
let maps = self.props.maps.sort((a, b) => {
|
||||
var aVotes = self.votesForMap(a);
|
||||
var bVotes = self.votesForMap(b);
|
||||
const aVotes = self.votesForMap(a);
|
||||
const bVotes = self.votesForMap(b);
|
||||
return bVotes - aVotes;
|
||||
}).map(map => {
|
||||
let votes = self.votesForMap(map);
|
||||
|
@ -594,13 +557,22 @@ var MapVoting = React.createClass({
|
|||
}
|
||||
})
|
||||
|
||||
var Gather = React.createClass({
|
||||
const Gather = exports.Gather = React.createClass({
|
||||
propTypes: {
|
||||
thisGatherer: React.PropTypes.object,
|
||||
maps: React.PropTypes.array.isRequired,
|
||||
servers: React.PropTypes.array.isRequired,
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
gather: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
let gather = this.props.gather;
|
||||
let thisGatherer = this.props.thisGatherer;
|
||||
let servers = this.props.servers;
|
||||
let maps = this.props.maps;
|
||||
let user = this.props.user;
|
||||
const socket = this.props.socket;
|
||||
const gather = this.props.gather;
|
||||
const thisGatherer = this.props.thisGatherer;
|
||||
const servers = this.props.servers;
|
||||
const maps = this.props.maps;
|
||||
const user = this.props.user;
|
||||
if (gather === null) return <div></div>;
|
||||
|
||||
let voting;
|
||||
|
@ -611,11 +583,11 @@ var Gather = React.createClass({
|
|||
<div className="row add-top">
|
||||
<div className="col-sm-6">
|
||||
<MapVoting gather={gather} maps={maps}
|
||||
thisGatherer={thisGatherer} />
|
||||
socket={socket} thisGatherer={thisGatherer} />
|
||||
</div>
|
||||
<div className="col-sm-6">
|
||||
<ServerVoting gather={gather} servers={servers}
|
||||
thisGatherer={thisGatherer} />
|
||||
socket={socket} thisGatherer={thisGatherer} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -638,12 +610,13 @@ var Gather = React.createClass({
|
|||
<div className="panel-heading">Current Gather</div>
|
||||
<div className="panel-body">
|
||||
<GatherProgress gather={gather} />
|
||||
<GatherActions gather={gather} user={user} thisGatherer={thisGatherer} />
|
||||
<GatherActions gather={gather} user={user} thisGatherer={thisGatherer}
|
||||
socket={socket} />
|
||||
</div>
|
||||
</div>
|
||||
<Gatherers gather={gather} user={user}
|
||||
soundController={this.props.soundController}
|
||||
thisGatherer={thisGatherer} />
|
||||
thisGatherer={thisGatherer} socket={socket} />
|
||||
{gatherTeams}
|
||||
{voting}
|
||||
</div>
|
||||
|
@ -654,7 +627,8 @@ var Gather = React.createClass({
|
|||
<div className="panel panel-primary add-bottom">
|
||||
<div className="panel-heading">Current Gather</div>
|
||||
</div>
|
||||
<Gatherers gather={gather} user={user} thisGatherer={thisGatherer} />
|
||||
<Gatherers gather={gather} user={user} thisGatherer={thisGatherer}
|
||||
socket={socket} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -662,7 +636,7 @@ var Gather = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var LifeformIcons = React.createClass({
|
||||
const LifeformIcons = exports.LifeformIcons = React.createClass({
|
||||
availableLifeforms() {
|
||||
return ["skulk", "gorge", "lerk", "fade", "onos", "commander"];
|
||||
},
|
||||
|
@ -700,32 +674,41 @@ var LifeformIcons = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var Gatherers = React.createClass({
|
||||
const Gatherers = React.createClass({
|
||||
propTypes: {
|
||||
user: React.PropTypes.object,
|
||||
thisGatherer: React.PropTypes.object,
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
gather: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
joinGather(e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:join");
|
||||
this.props.socket.emit("gather:join");
|
||||
},
|
||||
|
||||
bootGatherer(e) {
|
||||
e.preventDefault();
|
||||
socket.emit("gather:leave", {
|
||||
this.props.socket.emit("gather:leave", {
|
||||
gatherer: parseInt(e.target.value, 10) || null
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
let self = this;
|
||||
let user = this.props.user;
|
||||
let gather = this.props.gather;
|
||||
let admin = (user && user.admin) || (user && user.moderator);
|
||||
let thisGatherer = this.props.thisGatherer;
|
||||
let gatherers = gather.gatherers
|
||||
const self = this;
|
||||
const user = this.props.user;
|
||||
const socket = this.props.socket;
|
||||
const gather = this.props.gather;
|
||||
const thisGatherer = this.props.thisGatherer;
|
||||
const admin = (user && user.admin) || (user && user.moderator);
|
||||
const gatherers = gather.gatherers
|
||||
.sort((a, b) => {
|
||||
return (b.user.hive.skill || 1000) - (a.user.hive.skill || 1000);
|
||||
})
|
||||
.map(gatherer => {
|
||||
let country;
|
||||
if (gatherer.user.country) {
|
||||
var country = (
|
||||
country = (
|
||||
<img src="/blank.gif"
|
||||
className={"flag flag-" + gatherer.user.country.toLowerCase()}
|
||||
alt={gatherer.user.country} />
|
||||
|
@ -799,9 +782,8 @@ var Gatherers = React.createClass({
|
|||
onClick={this.bootGatherer}>
|
||||
Boot from Gather
|
||||
</button>
|
||||
<AssumeUserIdButton
|
||||
gatherer={gatherer}
|
||||
currentUser={user} />
|
||||
<AssumeUserIdButton socket={socket}
|
||||
gatherer={gatherer} currentUser={user} />
|
||||
</dd>
|
||||
]
|
||||
}
|
||||
|
@ -874,7 +856,7 @@ var Gatherers = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var CompletedGather = React.createClass({
|
||||
const CompletedGather = React.createClass({
|
||||
completionDate() {
|
||||
let d = new Date(this.props.gather.done.time);
|
||||
if (d) {
|
||||
|
@ -920,7 +902,7 @@ var CompletedGather = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var GatherVotingResults = React.createClass({
|
||||
const GatherVotingResults = React.createClass({
|
||||
// Returns an array of ids voted for e.g. [1,2,5,1,1,3,2]
|
||||
countVotes(voteType) {
|
||||
return this.props.gather.gatherers.reduce((acc, gatherer) => {
|
||||
|
@ -977,7 +959,13 @@ var GatherVotingResults = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var ArchivedGathers = React.createClass({
|
||||
const ArchivedGathers = exports.ArchivedGathers = React.createClass({
|
||||
propTypes: {
|
||||
archive: React.PropTypes.array.isRequired,
|
||||
servers: React.PropTypes.array.isRequired,
|
||||
maps: React.PropTypes.array.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
let archive = this.props.archive
|
||||
.sort((a, b) => {
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
import {Events} from "javascripts/components/event";
|
||||
import {CurrentUser, AdminPanel, ProfileModal, UserMenu} from "javascripts/components/user";
|
||||
import {SoundPanel} from "javascripts/components/sound";
|
||||
import {TeamSpeakButton, TeamSpeakModal} from "javascripts/components/teamspeak";
|
||||
import {SettingsPanel} from "javascripts/components/settings";
|
||||
import {Chatroom} from "javascripts/components/message";
|
||||
import {Gather, ArchivedGathers} from "javascripts/components/gather"
|
||||
|
||||
const React = require("react");
|
||||
const Gather = require("javascripts/components/gather").Gather;
|
||||
const ArchivedGather = require("javascripts/components/gather").ArchivedGather;
|
||||
const Event = require("javascripts/components/event");
|
||||
const Message = require("javascripts/components/message");
|
||||
const Settings = require("javascripts/components/settings");
|
||||
const Sound = require("javascripts/components/sound");
|
||||
const User = require("javascripts/components/user");
|
||||
const SoundController = Sound.SoundController;
|
||||
const helper = require("javascripts/helper");
|
||||
const storageAvailable = helper.storageAvailable;
|
||||
|
||||
const SplashScreen = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
status: "connecting", // connected, authFailed, banned
|
||||
status: "connecting",
|
||||
socket: null
|
||||
}
|
||||
},
|
||||
|
@ -22,10 +24,10 @@ const SplashScreen = React.createClass({
|
|||
let socket = io(socketUrl)
|
||||
.on("connect", () => {
|
||||
console.log("Connected");
|
||||
// removeAuthWidget();
|
||||
socket.on("reconnect", () => {
|
||||
this.setState({ status: "connected" });
|
||||
socket
|
||||
.on("reconnect", () => {
|
||||
console.log("Reconnected");
|
||||
this.setState({ status: "connected" });
|
||||
})
|
||||
.on("disconnect", () => {
|
||||
console.log("Disconnected")
|
||||
|
@ -45,23 +47,24 @@ const SplashScreen = React.createClass({
|
|||
|
||||
render() {
|
||||
const status = this.state.status;
|
||||
|
||||
if (status === "connected") {
|
||||
return <App socket={this.state.socket} />;
|
||||
}
|
||||
|
||||
let splash;
|
||||
if (status === "authFailed") {
|
||||
splash = <AuthFailedSplash />
|
||||
splash = <AuthFailedSplash />;
|
||||
} else if (status === "banned") {
|
||||
splash = <BannedSplash />
|
||||
} else {
|
||||
splash = <ConnectingSplash />
|
||||
splash = <BannedSplash />;
|
||||
} else if (status === "connecting") {
|
||||
splash = <ConnectingSplash />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style="min-height: 750px;">
|
||||
<div class="container-fluid">
|
||||
<div style={{"minHeight": "750px"}}>
|
||||
<div className="container-fluid">
|
||||
{splash}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -73,9 +76,9 @@ const SplashScreen = React.createClass({
|
|||
const AuthFailedSplash = React.createClass({
|
||||
render() {
|
||||
return (
|
||||
<div class="row" id="auth-required">
|
||||
<div class="col-lg-6 col-lg-offset-3">
|
||||
<div class="add-top jumbotron jumbo-auth text-center">
|
||||
<div className="row" id="auth-required">
|
||||
<div className="col-lg-6 col-lg-offset-3">
|
||||
<div className="add-top jumbotron jumbo-auth text-center">
|
||||
<div>
|
||||
<img src="/ensl_logo.png" alt="ENSL Logo" />
|
||||
</div>
|
||||
|
@ -83,7 +86,7 @@ const AuthFailedSplash = React.createClass({
|
|||
<h3><small>If you are logged on, try visiting a few pages on ENSL.org so the server can update your cookies</small></h3>
|
||||
<h3><small>If this error persists please contact an admin to fix it</small></h3>
|
||||
<br />
|
||||
<p><a class="btn btn-primary btn-lg" href="www.ensl.org" role="button">Go to website</a></p>
|
||||
<p><a className="btn btn-primary btn-lg" href="www.ensl.org" role="button">Go to website</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -134,6 +137,10 @@ const ConnectingSplash = React.createClass({
|
|||
});
|
||||
|
||||
const App = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
let updateTitle = true;
|
||||
let showEventsPanel = true;
|
||||
|
@ -147,15 +154,6 @@ const App = React.createClass({
|
|||
}
|
||||
}
|
||||
|
||||
return {
|
||||
events: [],
|
||||
updateTitle: updateTitle,
|
||||
showEventsPanel: showEventsPanel,
|
||||
soundController: new SoundController()
|
||||
};
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
gather: {
|
||||
gatherers: []
|
||||
|
@ -167,12 +165,15 @@ const App = React.createClass({
|
|||
servers: [],
|
||||
archive: [],
|
||||
socket: null,
|
||||
soundController: null
|
||||
events: [],
|
||||
updateTitle: updateTitle,
|
||||
showEventsPanel: showEventsPanel,
|
||||
soundController: new SoundController()
|
||||
};
|
||||
},
|
||||
|
||||
updateTitle() {
|
||||
let gather = this.props.gather;
|
||||
let gather = this.state.gather;
|
||||
if (gather && this.state.updateTitle) {
|
||||
document.title = `NSL Gathers (${gather.gatherers.length}/12)`;
|
||||
return;
|
||||
|
@ -198,8 +199,8 @@ const App = React.createClass({
|
|||
},
|
||||
|
||||
thisGatherer() {
|
||||
let gather = this.props.gather;
|
||||
let user = this.props.user;
|
||||
let gather = this.state.gather;
|
||||
let user = this.state.user;
|
||||
if (gather && user && gather.gatherers.length) {
|
||||
return gather.gatherers
|
||||
.filter(gatherer => gatherer.id === user.id)
|
||||
|
@ -239,15 +240,15 @@ const App = React.createClass({
|
|||
});
|
||||
|
||||
socket.on('users:update',
|
||||
data => self.setProps({
|
||||
data => self.setState({
|
||||
users: data.users,
|
||||
user: data.currentUser
|
||||
})
|
||||
);
|
||||
|
||||
socket.on("message:append", data => {
|
||||
self.setProps({
|
||||
messages: self.props.messages.concat(data.messages)
|
||||
self.setState({
|
||||
messages: self.state.messages.concat(data.messages)
|
||||
.sort((a, b) => {
|
||||
return new Date(a.createdAt) - new Date(b.createdAt);
|
||||
})
|
||||
|
@ -255,13 +256,13 @@ const App = React.createClass({
|
|||
});
|
||||
|
||||
socket.on("message:refresh", data => {
|
||||
self.setProps({
|
||||
self.setState({
|
||||
messages: data.messages
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("gather:refresh", (data) => {
|
||||
self.setProps({
|
||||
self.setState({
|
||||
gather: data.gather,
|
||||
maps: data.maps,
|
||||
servers: data.servers,
|
||||
|
@ -271,7 +272,7 @@ const App = React.createClass({
|
|||
});
|
||||
|
||||
socket.on("gather:archive:refresh", data => {
|
||||
self.setProps({
|
||||
self.setState({
|
||||
archive: data.archive,
|
||||
maps: data.maps,
|
||||
servers: data.servers
|
||||
|
@ -284,97 +285,136 @@ const App = React.createClass({
|
|||
},
|
||||
|
||||
render() {
|
||||
const socket = this.props.socket;
|
||||
|
||||
let eventsPanel;
|
||||
if (this.state.showEventsPanel) {
|
||||
eventsPanel = <Events events={this.state.events} />;
|
||||
}
|
||||
|
||||
return <div id="wrapper">
|
||||
<nav className="navbar navbar-default navbar-static-top"
|
||||
role="navigation"
|
||||
style={{marginBottom: "0"}}>
|
||||
<div className="navbar-header">
|
||||
<a className="navbar-brand" href="/">NSL Gathers <small><i>Alpha</i></small></a>
|
||||
</div>
|
||||
<ul className="nav navbar-top-links navbar-right" id="currentuser">
|
||||
<CurrentUser user={this.props.user} />
|
||||
let profileModal, chatroom, currentUser;
|
||||
if (this.state.user) {
|
||||
profileModal = <ProfileModal user={this.state.user} />;
|
||||
chatroom = <Chatroom messages={this.state.messages}
|
||||
user={this.state.user} socket={socket} />;
|
||||
currentUser = (
|
||||
<ul className="nav navbar-top-links navbar-right" id="currentuser">
|
||||
<CurrentUser user={this.state.user} />
|
||||
</ul>
|
||||
<ul className="nav navbar-top-links navbar-right" id="soundcontroller">
|
||||
<SoundPanel soundController={this.state.soundController} />
|
||||
</ul>
|
||||
<TeamSpeakButton />
|
||||
<ul className="nav navbar-top-links navbar-right">
|
||||
<li className="dropdown">
|
||||
<a className="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Info <i className="fa fa-caret-down"></i>
|
||||
</a>
|
||||
<ul className="dropdown-menu">
|
||||
<li>
|
||||
<a href="https://github.com/cblanc/sws_gathers" target="_blank">
|
||||
<i className="fa fa-github"> </i> Github
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://steamcommunity.com/id/nslgathers" target="_blank">
|
||||
<i className="fa fa-external-link"> </i> Steam Bot
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.ensl.org/articles/464" target="_blank">
|
||||
<i className="fa fa-external-link"> </i> Gather Rules
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/messages" target="_blank">
|
||||
<i className="fa fa-external-link"> </i> Message Archive
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<AdminPanel />
|
||||
<SettingsPanel
|
||||
toggleEventsPanel={this.toggleEventsPanel}
|
||||
showEventsPanel={this.state.showEventsPanel}
|
||||
toggleUpdateTitle={this.toggleUpdateTitle}
|
||||
updateTitle={this.state.updateTitle} />
|
||||
<TeamSpeakModal />
|
||||
<ProfileModal user={this.props.user} />
|
||||
<div style={{minHeight: "750px"}}>
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-2 hidden-xs">
|
||||
<ul className="nav" id="side-menu">
|
||||
<UserMenu users={this.props.users} user={this.props.user} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="wrapper">
|
||||
<header className="main-header">
|
||||
<a href="/" className="logo">
|
||||
<span className="logo-mini">NSL Gathers</span>
|
||||
<span className="logo-lg">NSL Gathers</span>
|
||||
</a>
|
||||
<nav className="navbar navbar-static-top" role="navigation">
|
||||
<a href="#" className="sidebar-toggle" data-toggle="offcanvas" role="button">
|
||||
<span className="sr-only">Toggle navigation</span>
|
||||
</a>
|
||||
<div className="navbar-custom-menu">
|
||||
<ul className="nav navbar-nav">
|
||||
<li className="dropdown messages-menu">
|
||||
<a href="#" className="dropdown-toggle" data-toggle="dropdown">
|
||||
<i className="fa fa-envelope-o"></i>
|
||||
<span className="label label-success">4</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div id="wrapper">
|
||||
<nav className="navbar navbar-default navbar-static-top"
|
||||
role="navigation"
|
||||
style={{marginBottom: "0"}}>
|
||||
<div className="navbar-header">
|
||||
<a className="navbar-brand" href="/">NSL Gathers <small><i>Alpha</i></small></a>
|
||||
</div>
|
||||
{currentUser}
|
||||
<ul className="nav navbar-top-links navbar-right" id="soundcontroller">
|
||||
<SoundPanel soundController={this.state.soundController} />
|
||||
</ul>
|
||||
<TeamSpeakButton />
|
||||
<ul className="nav navbar-top-links navbar-right">
|
||||
<li className="dropdown">
|
||||
<a className="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Info <i className="fa fa-caret-down"></i>
|
||||
</a>
|
||||
<ul className="dropdown-menu">
|
||||
<li>
|
||||
<a href="https://github.com/cblanc/sws_gathers" target="_blank">
|
||||
<i className="fa fa-github"> </i> Github
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://steamcommunity.com/id/nslgathers" target="_blank">
|
||||
<i className="fa fa-external-link"> </i> Steam Bot
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://www.ensl.org/articles/464" target="_blank">
|
||||
<i className="fa fa-external-link"> </i> Gather Rules
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/messages" target="_blank">
|
||||
<i className="fa fa-external-link"> </i> Message Archive
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col-md-4" id="chatroom">
|
||||
<Chatroom
|
||||
messages={this.props.messages}
|
||||
user={this.props.user} />
|
||||
</div>
|
||||
<div className="col-md-6" id="gathers">
|
||||
<Gather
|
||||
gather={this.props.gather}
|
||||
thisGatherer={this.thisGatherer()}
|
||||
user={this.props.user}
|
||||
soundController={this.state.soundController}
|
||||
maps={this.props.maps}
|
||||
servers={this.props.servers}
|
||||
previousGather={this.props.previousGather}/>
|
||||
<hr />
|
||||
<ArchivedGathers archive={this.props.archive}
|
||||
maps={this.props.maps}
|
||||
servers={this.props.servers} />
|
||||
<hr />
|
||||
{eventsPanel}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<AdminPanel socket={socket} />
|
||||
<SettingsPanel
|
||||
toggleEventsPanel={this.toggleEventsPanel}
|
||||
showEventsPanel={this.state.showEventsPanel}
|
||||
toggleUpdateTitle={this.toggleUpdateTitle}
|
||||
updateTitle={this.state.updateTitle} />
|
||||
<TeamSpeakModal />
|
||||
{profileModal}
|
||||
<div style={{minHeight: "750px"}}>
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-2 hidden-xs">
|
||||
<ul className="nav" id="side-menu">
|
||||
<UserMenu users={this.state.users} user={this.state.user}
|
||||
socket={socket} />
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col-md-4" id="chatroom">
|
||||
{chatroom}
|
||||
</div>
|
||||
<div className="col-md-6" id="gathers">
|
||||
<Gather
|
||||
socket={socket}
|
||||
maps={this.state.maps}
|
||||
user={this.state.user}
|
||||
gather={this.state.gather}
|
||||
servers={this.state.servers}
|
||||
thisGatherer={this.thisGatherer()}
|
||||
previousGather={this.state.previousGather}
|
||||
soundController={this.state.soundController} />
|
||||
{eventsPanel}
|
||||
<hr />
|
||||
<ArchivedGathers archive={this.state.archive}
|
||||
maps={this.state.maps}
|
||||
servers={this.state.servers} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = SplashScreen;
|
||||
module.exports = SplashScreen;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const React = require("react");
|
||||
const ReactDOM = require("react-dom");
|
||||
const ReactEmoji = require("react-emoji");
|
||||
const ReactAutolink = require("ReactAutolink");
|
||||
const ReactAutolink = require("react-autolink");
|
||||
const MessageBrowser = React.createClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
|
@ -173,7 +174,13 @@ const MessageBrowser = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var Chatroom = React.createClass({
|
||||
const Chatroom = exports.Chatroom = React.createClass({
|
||||
propTypes: {
|
||||
messages: React.PropTypes.array.isRequired,
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
user: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
autoScroll: true
|
||||
|
@ -190,7 +197,7 @@ var Chatroom = React.createClass({
|
|||
trailing: true
|
||||
});
|
||||
|
||||
let node = React.findDOMNode(this.refs.messageContainer);
|
||||
let node = ReactDOM.findDOMNode(this.refs.messageContainer);
|
||||
node.addEventListener('scroll', this.scrollListener);
|
||||
|
||||
this.scrollToBottom();
|
||||
|
@ -202,15 +209,15 @@ var Chatroom = React.createClass({
|
|||
},
|
||||
|
||||
loadMoreMessages() {
|
||||
var earliestMessage = this.props.messages[0];
|
||||
const earliestMessage = this.props.messages[0];
|
||||
if (earliestMessage === undefined) return;
|
||||
socket.emit("message:refresh", {
|
||||
this.props.socket.emit("message:refresh", {
|
||||
before: earliestMessage.createdAt
|
||||
});
|
||||
},
|
||||
|
||||
sendMessage(message) {
|
||||
socket.emit("newMessage", {message: message});
|
||||
this.props.socket.emit("newMessage", {message: message});
|
||||
},
|
||||
|
||||
clearAutoScrollTimeout() {
|
||||
|
@ -242,16 +249,17 @@ var Chatroom = React.createClass({
|
|||
|
||||
scrollToBottom() {
|
||||
if (!this.state.autoScroll) return;
|
||||
let node = React.findDOMNode(this.refs.messageContainer);
|
||||
let node = ReactDOM.findDOMNode(this.refs.messageContainer);
|
||||
node.scrollTop = node.scrollHeight;
|
||||
},
|
||||
|
||||
render() {
|
||||
let messages = this.props.messages.map(message => {
|
||||
const socket = this.props.socket;
|
||||
const messages = this.props.messages.map(message => {
|
||||
if (message) {
|
||||
return <ChatMessage message={message}
|
||||
key={message._id}
|
||||
id={message._id}
|
||||
socket={socket}
|
||||
user={this.props.user} />
|
||||
}
|
||||
});
|
||||
|
@ -271,16 +279,22 @@ var Chatroom = React.createClass({
|
|||
</ul>
|
||||
</div>
|
||||
<div className="panel-footer">
|
||||
<MessageBar />
|
||||
<MessageBar socket={socket}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var imgurRegex = /^(https?:\/\/i\.imgur\.com\/\S*\.(jpg|png))$/i;
|
||||
const imgurRegex = /^(https?:\/\/i\.imgur\.com\/\S*\.(jpg|png))$/i;
|
||||
|
||||
const ChatMessage = React.createClass({
|
||||
propTypes: {
|
||||
user: React.PropTypes.object.isRequired,
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
message: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
var ChatMessage = React.createClass({
|
||||
mixins: [
|
||||
ReactAutolink,
|
||||
ReactEmoji
|
||||
|
@ -342,7 +356,8 @@ var ChatMessage = React.createClass({
|
|||
let deleteButton;
|
||||
let user = this.props.user;
|
||||
if (user && user.admin) {
|
||||
deleteButton = <DeleteMessageButton messageId={this.props.message._id} />;
|
||||
deleteButton = <DeleteMessageButton messageId={this.props.message._id}
|
||||
socket={this.props.socket}/>;
|
||||
}
|
||||
return (
|
||||
<li className="left clearfix">
|
||||
|
@ -374,10 +389,14 @@ var ChatMessage = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var DeleteMessageButton = React.createClass({
|
||||
const DeleteMessageButton = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
handleClick (e) {
|
||||
e.preventDefault();
|
||||
socket.emit("message:delete", {
|
||||
this.props.socket.emit("message:delete", {
|
||||
id: this.props.messageId
|
||||
});
|
||||
},
|
||||
|
@ -391,9 +410,13 @@ var DeleteMessageButton = React.createClass({
|
|||
}
|
||||
})
|
||||
|
||||
var MessageBar = React.createClass({
|
||||
const MessageBar = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
sendMessage(content) {
|
||||
socket.emit("message:new", {
|
||||
this.props.socket.emit("message:new", {
|
||||
content: content
|
||||
});
|
||||
},
|
||||
|
@ -405,7 +428,7 @@ var MessageBar = React.createClass({
|
|||
},
|
||||
|
||||
checkInputLength() {
|
||||
const input = React.findDOMNode(this.refs.content).value;
|
||||
const input = ReactDOM.findDOMNode(this.refs.content).value;
|
||||
const currentStatusMessage = this.state.statusMessage;
|
||||
if (input.length > 256) {
|
||||
return this.setState({
|
||||
|
@ -425,9 +448,9 @@ var MessageBar = React.createClass({
|
|||
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
let content = React.findDOMNode(this.refs.content).value.trim();
|
||||
let content = ReactDOM.findDOMNode(this.refs.content).value.trim();
|
||||
if (!content) return;
|
||||
React.findDOMNode(this.refs.content).value = '';
|
||||
ReactDOM.findDOMNode(this.refs.content).value = '';
|
||||
this.sendMessage(content);
|
||||
return;
|
||||
},
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
const React = require("react");
|
||||
|
||||
const SettingsPanel = React.createClass({
|
||||
const SettingsPanel = exports.SettingsPanel = React.createClass({
|
||||
propTypes: {
|
||||
toggleUpdateTitle: React.PropTypes.func.isRequired,
|
||||
updateTitle: React.PropTypes.bool.isRequired,
|
||||
toggleEventsPanel: React.PropTypes.func.isRequired,
|
||||
showEventsPanel: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="modal fade" id="settingsmodal">
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
const Howl = require("howl");
|
||||
const $ = require("jquery");
|
||||
const React = require("react");
|
||||
const Howl = require("howler").Howl;
|
||||
const Howler = require("howler").Howler;
|
||||
const helper = require("javascripts/helper");
|
||||
const storageAvailable = helper.storageAvailable;
|
||||
|
||||
|
@ -278,3 +280,8 @@ var SoundPanel = React.createClass({
|
|||
</ul>;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
SoundController: SoundController,
|
||||
SoundPanel: SoundPanel
|
||||
};
|
||||
|
|
83
app/javascripts/components/teamspeak.js
Normal file
83
app/javascripts/components/teamspeak.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
const React = require("react");
|
||||
|
||||
const teamspeakDefaults = {
|
||||
url: "ts3server://ensl.org/",
|
||||
password: "ns2gather",
|
||||
alien: {
|
||||
channel: "NS2 Gather/Gather #1/Alien",
|
||||
password: "ns2gather"
|
||||
},
|
||||
marine: {
|
||||
channel: "NS2 Gather/Gather #1/Marine",
|
||||
password: "ns2gather"
|
||||
}
|
||||
};
|
||||
|
||||
var TeamSpeakButton = exports.TeamSpeakButton = React.createClass({
|
||||
getDefaultProps() {
|
||||
return teamspeakDefaults
|
||||
},
|
||||
marineUrl() {
|
||||
return this.teamSpeakUrl(this.props.marine);
|
||||
},
|
||||
alienUrl() {
|
||||
return this.teamSpeakUrl(this.props.alien);
|
||||
},
|
||||
teamSpeakUrl(conn) {
|
||||
let params = `channel=${encodeURIComponent(conn.channel)}&
|
||||
channelpassword=${encodeURIComponent(conn.password)}`;
|
||||
return (`${this.props.url}?${params}`);
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<ul className="nav navbar-top-links navbar-right">
|
||||
<li className="dropdown">
|
||||
<a className="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Teamspeak <i className="fa fa-caret-down"></i>
|
||||
</a>
|
||||
<ul className="dropdown-menu">
|
||||
<li><a href={this.props.url}>Join Teamspeak Lobby</a></li>
|
||||
<li><a href={this.marineUrl()}>Join Marine Teamspeak</a></li>
|
||||
<li><a href={this.alienUrl()}>Join Alien Teamspeak</a></li>
|
||||
<li role="separator" className="divider"></li>
|
||||
<li><a href="#" data-toggle="modal" data-target="#teamspeakmodal">Teamspeak Details</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var TeamSpeakModal = exports.TeamSpeakModal = React.createClass({
|
||||
getDefaultProps() {
|
||||
return teamspeakDefaults;
|
||||
},
|
||||
|
||||
render() {
|
||||
return <div className="modal fade text-left" id="teamspeakmodal">
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<button type="button"
|
||||
className="close"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 className="modal-title">Teamspeak Server Information</h4>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<dl className="dl-horizontal">
|
||||
<dt>Server</dt>
|
||||
<dd>{this.props.url}</dd>
|
||||
<dt>Password</dt>
|
||||
<dd>{this.props.password}</dd>
|
||||
<dt>Marine Channel</dt>
|
||||
<dd>{this.props.marine.channel}</dd>
|
||||
<dt>Alien Channel</dt>
|
||||
<dd>{this.props.alien.channel}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
});
|
|
@ -1,3 +1,4 @@
|
|||
import {LifeformIcons} from "javascripts/components/gather";
|
||||
const React = require("react");
|
||||
const helper = require("javascripts/helper");
|
||||
const enslUrl = helper.enslUrl;
|
||||
|
@ -5,8 +6,12 @@ const hiveUrl = helper.hiveUrl;
|
|||
const modalId = helper.modalId;
|
||||
|
||||
const UserLogin = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
authorizeId(id) {
|
||||
socket.emit("users:authorize", {
|
||||
this.props.socket.emit("users:authorize", {
|
||||
id: parseInt(id, 10)
|
||||
});
|
||||
},
|
||||
|
@ -43,6 +48,11 @@ const UserLogin = React.createClass({
|
|||
});
|
||||
|
||||
const DisconnectUserButton = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
id: React.PropTypes.number.isRequired
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
id: null
|
||||
|
@ -50,7 +60,7 @@ const DisconnectUserButton = React.createClass({
|
|||
},
|
||||
|
||||
disconnectUser() {
|
||||
socket.emit("users:disconnect", {
|
||||
this.props.socket.emit("users:disconnect", {
|
||||
id: this.props.id
|
||||
});
|
||||
},
|
||||
|
@ -64,38 +74,44 @@ const DisconnectUserButton = React.createClass({
|
|||
});
|
||||
|
||||
const UserModal = React.createClass({
|
||||
propTypes: {
|
||||
user: React.PropTypes.object.isRequired,
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
currentUser: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
const currentUser = this.props.currentUser;
|
||||
const user = this.props.user;
|
||||
let hiveStats;
|
||||
if (user.hive.id) {
|
||||
hiveStats = [
|
||||
<tr><td><strong>Hive Stats</strong></td><td></td></tr>,
|
||||
<tr>
|
||||
<tr key="stats"><td><strong>Hive Stats</strong></td><td></td></tr>,
|
||||
<tr key="elo">
|
||||
<td>ELO</td>
|
||||
<td>{user.hive.skill}</td>
|
||||
</tr>,
|
||||
<tr>
|
||||
<tr key="hours">
|
||||
<td>Hours Played</td>
|
||||
<td>{Math.round(user.hive.playTime / 3600)}</td>
|
||||
</tr>,
|
||||
<tr>
|
||||
<tr key="wins">
|
||||
<td>Wins</td>
|
||||
<td>{user.hive.wins}</td>
|
||||
</tr>,
|
||||
<tr>
|
||||
<tr key="losses">
|
||||
<td>Losses</td>
|
||||
<td>{user.hive.loses}</td>
|
||||
</tr>,
|
||||
<tr>
|
||||
<tr key="kills">
|
||||
<td>Kills (/min)</td>
|
||||
<td>{user.hive.kills} ({_.round(user.hive.kills / (user.hive.playTime / 60), 1)})</td>
|
||||
</tr>,
|
||||
<tr>
|
||||
<tr key="assists">
|
||||
<td>Assists (/min)</td>
|
||||
<td>{user.hive.assists} ({_.round(user.hive.assists / (user.hive.playTime / 60), 1)})</td>
|
||||
</tr>,
|
||||
<tr>
|
||||
<tr key="deaths">
|
||||
<td>Deaths (/min)</td>
|
||||
<td>{user.hive.deaths} ({_.round(user.hive.deaths / (user.hive.playTime / 60), 1)})</td>
|
||||
</tr>
|
||||
|
@ -103,7 +119,7 @@ const UserModal = React.createClass({
|
|||
}
|
||||
let adminOptions;
|
||||
if (currentUser.admin) {
|
||||
adminOptions = <DisconnectUserButton id={user.id} />;
|
||||
adminOptions = <DisconnectUserButton id={user.id} socket={this.props.socket} />;
|
||||
}
|
||||
return (
|
||||
<div className="modal fade" id={modalId(user)}>
|
||||
|
@ -163,6 +179,12 @@ const UserModal = React.createClass({
|
|||
})
|
||||
|
||||
const UserItem = React.createClass({
|
||||
propTypes: {
|
||||
user: React.PropTypes.object.isRequired,
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
currentUser: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
const user = this.props.user;
|
||||
const currentUser = this.props.currentUser;
|
||||
|
@ -170,19 +192,25 @@ const UserItem = React.createClass({
|
|||
<li className="list-group-item">
|
||||
<a href="#" data-toggle="modal"
|
||||
data-target={`#${modalId(user)}`}>{user.username}</a>
|
||||
<UserModal user={user} currentUser={currentUser} />
|
||||
<UserModal user={user} currentUser={currentUser}
|
||||
socket={this.props.socket} />
|
||||
</li>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const UserMenu = React.createClass({
|
||||
const UserMenu = exports.UserMenu = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
users: React.PropTypes.array.isRequired
|
||||
},
|
||||
|
||||
render() {
|
||||
const users = this.props.users
|
||||
.sort((a, b) => (a.username.toLowerCase() > b.username.toLowerCase()) ? 1 : -1)
|
||||
.map(user => {
|
||||
return <UserItem user={user} key={user.id}
|
||||
currentUser={this.props.user} />
|
||||
currentUser={this.props.user} socket={this.props.socket} />
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
|
@ -200,9 +228,13 @@ const UserMenu = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
const AdminPanel = React.createClass({
|
||||
const AdminPanel = exports.AdminPanel = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
handleGatherReset() {
|
||||
socket.emit("gather:reset");
|
||||
this.props.socket.emit("gather:reset");
|
||||
},
|
||||
|
||||
render() {
|
||||
|
@ -219,7 +251,7 @@ const AdminPanel = React.createClass({
|
|||
</div>
|
||||
<div className="modal-body" id="admin-menu">
|
||||
<h5>Swap Into a Different Account (Only works for admins)</h5>
|
||||
<UserLogin />
|
||||
<UserLogin socket={this.props.socket} />
|
||||
<h5>Gather Options</h5>
|
||||
<div>
|
||||
<button
|
||||
|
@ -239,7 +271,11 @@ const AdminPanel = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
const ProfileModal = React.createClass({
|
||||
const ProfileModal = exports.ProfileModal = React.createClass({
|
||||
propTypes: {
|
||||
user: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
handleUserUpdate(e) {
|
||||
e.preventDefault();
|
||||
let abilities = {
|
||||
|
@ -336,7 +372,7 @@ const ProfileModal = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
const CurrentUser = React.createClass({
|
||||
const CurrentUser = exports.CurrentUser = React.createClass({
|
||||
render() {
|
||||
if (this.props.user) {
|
||||
let adminOptions;
|
||||
|
@ -378,16 +414,22 @@ const CurrentUser = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
var AssumeUserIdButton = React.createClass({
|
||||
var AssumeUserIdButton = exports.AssumeUserIdButton = React.createClass({
|
||||
propTypes: {
|
||||
socket: React.PropTypes.object.isRequired,
|
||||
gatherer: React.PropTypes.object.isRequired,
|
||||
currentUser: React.PropTypes.object.isRequired,
|
||||
},
|
||||
|
||||
assumeId(e) {
|
||||
e.preventDefault();
|
||||
if (this.props.gatherer) {
|
||||
socket.emit("users:authorize", {
|
||||
this.props.socket.emit("users:authorize", {
|
||||
id: this.props.gatherer.id
|
||||
});
|
||||
// Refresh Gather list
|
||||
setTimeout(() => {
|
||||
socket.emit("gather:refresh");
|
||||
this.props.socket.emit("gather:refresh");
|
||||
}, 5000);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -212,4 +212,14 @@ html, body {
|
|||
color: #839496;
|
||||
border-color: #428bca;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix for solarize theme */
|
||||
|
||||
.badge {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.gather-voting {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -36,7 +36,7 @@ exports.config = {
|
|||
babel: {
|
||||
presets: ["es2015", "react"],
|
||||
// Do not use ES6 compiler in vendor code
|
||||
ignore: [/web\/static\/vendor/]
|
||||
ignore: [/vendor/]
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -50,11 +50,11 @@ exports.config = {
|
|||
npm: {
|
||||
enabled: true,
|
||||
styles: {
|
||||
"bootstrap": ["dist/css/bootstrap.min.css"]
|
||||
"bootstrap-solarized": ["bootstrap-solarized-dark.css"]
|
||||
},
|
||||
whitelist: ["react", "react-dom", "jquery", "lodash",
|
||||
"react-autolink-text", "react-dom", "react-emoji",
|
||||
"bootstrap", "bootstrap-slider"],
|
||||
"react-autolink", "react-dom", "react-emoji", "howler",
|
||||
"bootstrap"],
|
||||
globals: {
|
||||
"_": "lodash",
|
||||
"jQuery": "jquery",
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
"start": "npm run compile && node index.js",
|
||||
"start_production": "npm run compile_production && node index.js",
|
||||
"watch": "npm run compile && node_modules/brunch/bin/brunch watch --server",
|
||||
"compile": "node_modules/brunch/bin/brunch build",
|
||||
"compile_production": "node_modules/brunch/bin/brunch build --production",
|
||||
"compile": "node node_modules/brunch/bin/brunch build",
|
||||
"compile_production": "node node_modules/brunch/bin/brunch build --production",
|
||||
"dev": "nodemon index.js"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -35,7 +35,7 @@
|
|||
"babel-preset-es2015": "~6.3.13",
|
||||
"babel-preset-react": "~6.3.13",
|
||||
"bootstrap": "~3.3.6",
|
||||
"bootstrap-slider": "^6.0.7",
|
||||
"bootstrap-solarized": "~1.0.2",
|
||||
"brunch": "~2.1.3",
|
||||
"clean-css-brunch": ">= 1.0 < 1.8",
|
||||
"cookie-parser": "~1.3.5",
|
||||
|
@ -44,6 +44,7 @@
|
|||
"express": "~4.13.1",
|
||||
"express-handlebars": "~2.0.1",
|
||||
"extend": "~3.0.0",
|
||||
"howler": "~1.1.28",
|
||||
"javascript-brunch": ">= 1.0 < 1.8",
|
||||
"javascript-state-machine": "~2.3.5",
|
||||
"jquery": "~2.2.0",
|
||||
|
@ -52,7 +53,7 @@
|
|||
"morgan": "~1.6.1",
|
||||
"newrelic": "~1.22.1",
|
||||
"react": "~0.14.6",
|
||||
"react-autolink-text": "joshparolin/react-autolink-text",
|
||||
"react-autolink": "~0.2.1",
|
||||
"react-dom": "~0.14.6",
|
||||
"react-emoji": "~0.4.1",
|
||||
"request": "~2.60.0",
|
||||
|
|
10882
public/app.css
10882
public/app.css
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
917
public/app.js
917
public/app.js
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
17943
public/vendor.js
17943
public/vendor.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
29
vendor/slider.min.js
vendored
Normal file
29
vendor/slider.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
784
vendor/theme.js
vendored
784
vendor/theme.js
vendored
|
@ -1,46 +1,758 @@
|
|||
/*
|
||||
* metismenu - v2.0.2
|
||||
* A jQuery menu plugin
|
||||
* https://github.com/onokumus/metisMenu
|
||||
/*! AdminLTE app.js
|
||||
* ================
|
||||
* Main JS application file for AdminLTE v2. This file
|
||||
* should be included in all pages. It controls some layout
|
||||
* options and implements exclusive AdminLTE plugins.
|
||||
*
|
||||
* Made by Osman Nuri Okumus
|
||||
* Under MIT License
|
||||
* @Author Almsaeed Studio
|
||||
* @Support <http://www.almsaeedstudio.com>
|
||||
* @Email <support@almsaeedstudio.com>
|
||||
* @version 2.3.2
|
||||
* @license MIT <http://opensource.org/licenses/MIT>
|
||||
*/
|
||||
|
||||
!function(a){"use strict";function b(){var a=document.createElement("mm"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}function c(b){return this.each(function(){var c=a(this),d=c.data("mm"),f=a.extend({},e.DEFAULTS,c.data(),"object"==typeof b&&b);d||c.data("mm",d=new e(this,f)),"string"==typeof b&&d[b]()})}a.fn.emulateTransitionEnd=function(b){var c=!1,e=this;a(this).one("mmTransitionEnd",function(){c=!0});var f=function(){c||a(e).trigger(d.end)};return setTimeout(f,b),this};var d=b();d&&(a.event.special.mmTransitionEnd={bindType:d.end,delegateType:d.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}});var e=function(b,c){this.$element=a(b),this.options=a.extend({},e.DEFAULTS,c),this.transitioning=null,this.init()};e.TRANSITION_DURATION=350,e.DEFAULTS={toggle:!0,doubleTapToGo:!1,activeClass:"active",collapseClass:"collapse",collapseInClass:"in",collapsingClass:"collapsing"},e.prototype.init=function(){var b=this,c=this.options.activeClass,d=this.options.collapseClass,e=this.options.collapseInClass;this.$element.find("li."+c).has("ul").children("ul").addClass(d+" "+e),this.$element.find("li").not("."+c).has("ul").children("ul").addClass(d),this.options.doubleTapToGo&&this.$element.find("li."+c).has("ul").children("a").addClass("doubleTapToGo"),this.$element.find("li").has("ul").children("a").on("click.metisMenu",function(d){var e=a(this),f=e.parent("li"),g=f.children("ul");return d.preventDefault(),f.hasClass(c)?b.hide(g):b.show(g),b.options.doubleTapToGo&&b.doubleTapToGo(e)&&"#"!==e.attr("href")&&""!==e.attr("href")?(d.stopPropagation(),void(document.location=e.attr("href"))):void 0})},e.prototype.doubleTapToGo=function(a){var b=this.$element;return a.hasClass("doubleTapToGo")?(a.removeClass("doubleTapToGo"),!0):a.parent().children("ul").length?(b.find(".doubleTapToGo").removeClass("doubleTapToGo"),a.addClass("doubleTapToGo"),!1):void 0},e.prototype.show=function(b){var c=this.options.activeClass,f=this.options.collapseClass,g=this.options.collapseInClass,h=this.options.collapsingClass,i=a(b),j=i.parent("li");if(!this.transitioning&&!i.hasClass(g)){j.addClass(c),this.options.toggle&&this.hide(j.siblings().children("ul."+g)),i.removeClass(f).addClass(h).height(0),this.transitioning=1;var k=function(){i.removeClass(h).addClass(f+" "+g).height(""),this.transitioning=0};return d?void i.one("mmTransitionEnd",a.proxy(k,this)).emulateTransitionEnd(e.TRANSITION_DURATION).height(i[0].scrollHeight):k.call(this)}},e.prototype.hide=function(b){var c=this.options.activeClass,f=this.options.collapseClass,g=this.options.collapseInClass,h=this.options.collapsingClass,i=a(b);if(!this.transitioning&&i.hasClass(g)){i.parent("li").removeClass(c),i.height(i.height())[0].offsetHeight,i.addClass(h).removeClass(f).removeClass(g),this.transitioning=1;var j=function(){this.transitioning=0,i.removeClass(h).addClass(f)};return d?void i.height(0).one("mmTransitionEnd",a.proxy(j,this)).emulateTransitionEnd(e.TRANSITION_DURATION):j.call(this)}};var f=a.fn.metisMenu;a.fn.metisMenu=c,a.fn.metisMenu.Constructor=e,a.fn.metisMenu.noConflict=function(){return a.fn.metisMenu=f,this}}(jQuery);
|
||||
//Make sure jQuery has been loaded before app.js
|
||||
if (typeof jQuery === "undefined") {
|
||||
throw new Error("AdminLTE requires jQuery");
|
||||
}
|
||||
|
||||
/* AdminLTE
|
||||
*
|
||||
* @type Object
|
||||
* @description $.AdminLTE is the main object for the template's app.
|
||||
* It's used for implementing functions and options related
|
||||
* to the template. Keeping everything wrapped in an object
|
||||
* prevents conflict with other plugins and is a better
|
||||
* way to organize our code.
|
||||
*/
|
||||
$.AdminLTE = {};
|
||||
|
||||
$(function() {
|
||||
$('#side-menu').metisMenu();
|
||||
});
|
||||
/* --------------------
|
||||
* - AdminLTE Options -
|
||||
* --------------------
|
||||
* Modify these options to suit your implementation
|
||||
*/
|
||||
$.AdminLTE.options = {
|
||||
//Add slimscroll to navbar menus
|
||||
//This requires you to load the slimscroll plugin
|
||||
//in every page before app.js
|
||||
navbarMenuSlimscroll: true,
|
||||
navbarMenuSlimscrollWidth: "3px", //The width of the scroll bar
|
||||
navbarMenuHeight: "200px", //The height of the inner menu
|
||||
//General animation speed for JS animated elements such as box collapse/expand and
|
||||
//sidebar treeview slide up/down. This options accepts an integer as milliseconds,
|
||||
//'fast', 'normal', or 'slow'
|
||||
animationSpeed: 500,
|
||||
//Sidebar push menu toggle button selector
|
||||
sidebarToggleSelector: "[data-toggle='offcanvas']",
|
||||
//Activate sidebar push menu
|
||||
sidebarPushMenu: true,
|
||||
//Activate sidebar slimscroll if the fixed layout is set (requires SlimScroll Plugin)
|
||||
sidebarSlimScroll: true,
|
||||
//Enable sidebar expand on hover effect for sidebar mini
|
||||
//This option is forced to true if both the fixed layout and sidebar mini
|
||||
//are used together
|
||||
sidebarExpandOnHover: false,
|
||||
//BoxRefresh Plugin
|
||||
enableBoxRefresh: true,
|
||||
//Bootstrap.js tooltip
|
||||
enableBSToppltip: true,
|
||||
BSTooltipSelector: "[data-toggle='tooltip']",
|
||||
//Enable Fast Click. Fastclick.js creates a more
|
||||
//native touch experience with touch devices. If you
|
||||
//choose to enable the plugin, make sure you load the script
|
||||
//before AdminLTE's app.js
|
||||
enableFastclick: true,
|
||||
//Control Sidebar Options
|
||||
enableControlSidebar: true,
|
||||
controlSidebarOptions: {
|
||||
//Which button should trigger the open/close event
|
||||
toggleBtnSelector: "[data-toggle='control-sidebar']",
|
||||
//The sidebar selector
|
||||
selector: ".control-sidebar",
|
||||
//Enable slide over content
|
||||
slide: true
|
||||
},
|
||||
//Box Widget Plugin. Enable this plugin
|
||||
//to allow boxes to be collapsed and/or removed
|
||||
enableBoxWidget: true,
|
||||
//Box Widget plugin options
|
||||
boxWidgetOptions: {
|
||||
boxWidgetIcons: {
|
||||
//Collapse icon
|
||||
collapse: 'fa-minus',
|
||||
//Open icon
|
||||
open: 'fa-plus',
|
||||
//Remove icon
|
||||
remove: 'fa-times'
|
||||
},
|
||||
boxWidgetSelectors: {
|
||||
//Remove button selector
|
||||
remove: '[data-widget="remove"]',
|
||||
//Collapse button selector
|
||||
collapse: '[data-widget="collapse"]'
|
||||
}
|
||||
},
|
||||
//Direct Chat plugin options
|
||||
directChat: {
|
||||
//Enable direct chat by default
|
||||
enable: true,
|
||||
//The button to open and close the chat contacts pane
|
||||
contactToggleSelector: '[data-widget="chat-pane-toggle"]'
|
||||
},
|
||||
//Define the set of colors to use globally around the website
|
||||
colors: {
|
||||
lightBlue: "#3c8dbc",
|
||||
red: "#f56954",
|
||||
green: "#00a65a",
|
||||
aqua: "#00c0ef",
|
||||
yellow: "#f39c12",
|
||||
blue: "#0073b7",
|
||||
navy: "#001F3F",
|
||||
teal: "#39CCCC",
|
||||
olive: "#3D9970",
|
||||
lime: "#01FF70",
|
||||
orange: "#FF851B",
|
||||
fuchsia: "#F012BE",
|
||||
purple: "#8E24AA",
|
||||
maroon: "#D81B60",
|
||||
black: "#222222",
|
||||
gray: "#d2d6de"
|
||||
},
|
||||
//The standard screen sizes that bootstrap uses.
|
||||
//If you change these in the variables.less file, change
|
||||
//them here too.
|
||||
screenSizes: {
|
||||
xs: 480,
|
||||
sm: 768,
|
||||
md: 992,
|
||||
lg: 1200
|
||||
}
|
||||
};
|
||||
|
||||
//Loads the correct sidebar on window load,
|
||||
//collapses the sidebar on window resize.
|
||||
// Sets the min-height of #page-wrapper to window size
|
||||
$(function() {
|
||||
$(window).bind("load resize", function() {
|
||||
topOffset = 50;
|
||||
width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width;
|
||||
if (width < 768) {
|
||||
$('div.navbar-collapse').addClass('collapse');
|
||||
topOffset = 100; // 2-row-menu
|
||||
} else {
|
||||
$('div.navbar-collapse').removeClass('collapse');
|
||||
}
|
||||
/* ------------------
|
||||
* - Implementation -
|
||||
* ------------------
|
||||
* The next block of code implements AdminLTE's
|
||||
* functions and plugins as specified by the
|
||||
* options above.
|
||||
*/
|
||||
$(function () {
|
||||
"use strict";
|
||||
|
||||
height = ((this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height) - 1;
|
||||
height = height - topOffset;
|
||||
if (height < 1) height = 1;
|
||||
if (height > topOffset) {
|
||||
$("#page-wrapper").css("min-height", (height) + "px");
|
||||
}
|
||||
//Fix for IE page transitions
|
||||
$("body").removeClass("hold-transition");
|
||||
|
||||
//Extend options if external options exist
|
||||
if (typeof AdminLTEOptions !== "undefined") {
|
||||
$.extend(true,
|
||||
$.AdminLTE.options,
|
||||
AdminLTEOptions);
|
||||
}
|
||||
|
||||
//Easy access to options
|
||||
var o = $.AdminLTE.options;
|
||||
|
||||
//Set up the object
|
||||
_init();
|
||||
|
||||
//Activate the layout maker
|
||||
$.AdminLTE.layout.activate();
|
||||
|
||||
//Enable sidebar tree view controls
|
||||
$.AdminLTE.tree('.sidebar');
|
||||
|
||||
//Enable control sidebar
|
||||
if (o.enableControlSidebar) {
|
||||
$.AdminLTE.controlSidebar.activate();
|
||||
}
|
||||
|
||||
//Add slimscroll to navbar dropdown
|
||||
if (o.navbarMenuSlimscroll && typeof $.fn.slimscroll != 'undefined') {
|
||||
$(".navbar .menu").slimscroll({
|
||||
height: o.navbarMenuHeight,
|
||||
alwaysVisible: false,
|
||||
size: o.navbarMenuSlimscrollWidth
|
||||
}).css("width", "100%");
|
||||
}
|
||||
|
||||
//Activate sidebar push menu
|
||||
if (o.sidebarPushMenu) {
|
||||
$.AdminLTE.pushMenu.activate(o.sidebarToggleSelector);
|
||||
}
|
||||
|
||||
//Activate Bootstrap tooltip
|
||||
if (o.enableBSToppltip) {
|
||||
$('body').tooltip({
|
||||
selector: o.BSTooltipSelector
|
||||
});
|
||||
}
|
||||
|
||||
//Activate box widget
|
||||
if (o.enableBoxWidget) {
|
||||
$.AdminLTE.boxWidget.activate();
|
||||
}
|
||||
|
||||
//Activate fast click
|
||||
if (o.enableFastclick && typeof FastClick != 'undefined') {
|
||||
FastClick.attach(document.body);
|
||||
}
|
||||
|
||||
//Activate direct chat widget
|
||||
if (o.directChat.enable) {
|
||||
$(document).on('click', o.directChat.contactToggleSelector, function () {
|
||||
var box = $(this).parents('.direct-chat').first();
|
||||
box.toggleClass('direct-chat-contacts-open');
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* INITIALIZE BUTTON TOGGLE
|
||||
* ------------------------
|
||||
*/
|
||||
$('.btn-group[data-toggle="btn-toggle"]').each(function () {
|
||||
var group = $(this);
|
||||
$(this).find(".btn").on('click', function (e) {
|
||||
group.find(".btn.active").removeClass("active");
|
||||
$(this).addClass("active");
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
var url = window.location;
|
||||
var element = $('ul.nav a').filter(function() {
|
||||
return this.href == url || url.href.indexOf(this.href) == 0;
|
||||
}).addClass('active').parent().parent().addClass('in').parent();
|
||||
if (element.is('li')) {
|
||||
element.addClass('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* ----------------------------------
|
||||
* - Initialize the AdminLTE Object -
|
||||
* ----------------------------------
|
||||
* All AdminLTE functions are implemented below.
|
||||
*/
|
||||
function _init() {
|
||||
'use strict';
|
||||
/* Layout
|
||||
* ======
|
||||
* Fixes the layout height in case min-height fails.
|
||||
*
|
||||
* @type Object
|
||||
* @usage $.AdminLTE.layout.activate()
|
||||
* $.AdminLTE.layout.fix()
|
||||
* $.AdminLTE.layout.fixSidebar()
|
||||
*/
|
||||
$.AdminLTE.layout = {
|
||||
activate: function () {
|
||||
var _this = this;
|
||||
_this.fix();
|
||||
_this.fixSidebar();
|
||||
$(window, ".wrapper").resize(function () {
|
||||
_this.fix();
|
||||
_this.fixSidebar();
|
||||
});
|
||||
},
|
||||
fix: function () {
|
||||
//Get window height and the wrapper height
|
||||
var neg = $('.main-header').outerHeight() + $('.main-footer').outerHeight();
|
||||
var window_height = $(window).height();
|
||||
var sidebar_height = $(".sidebar").height();
|
||||
//Set the min-height of the content and sidebar based on the
|
||||
//the height of the document.
|
||||
if ($("body").hasClass("fixed")) {
|
||||
$(".content-wrapper, .right-side").css('min-height', window_height - $('.main-footer').outerHeight());
|
||||
} else {
|
||||
var postSetWidth;
|
||||
if (window_height >= sidebar_height) {
|
||||
$(".content-wrapper, .right-side").css('min-height', window_height - neg);
|
||||
postSetWidth = window_height - neg;
|
||||
} else {
|
||||
$(".content-wrapper, .right-side").css('min-height', sidebar_height);
|
||||
postSetWidth = sidebar_height;
|
||||
}
|
||||
|
||||
//Fix for the control sidebar height
|
||||
var controlSidebar = $($.AdminLTE.options.controlSidebarOptions.selector);
|
||||
if (typeof controlSidebar !== "undefined") {
|
||||
if (controlSidebar.height() > postSetWidth)
|
||||
$(".content-wrapper, .right-side").css('min-height', controlSidebar.height());
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
fixSidebar: function () {
|
||||
//Make sure the body tag has the .fixed class
|
||||
if (!$("body").hasClass("fixed")) {
|
||||
if (typeof $.fn.slimScroll != 'undefined') {
|
||||
$(".sidebar").slimScroll({destroy: true}).height("auto");
|
||||
}
|
||||
return;
|
||||
} else if (typeof $.fn.slimScroll == 'undefined' && window.console) {
|
||||
window.console.error("Error: the fixed layout requires the slimscroll plugin!");
|
||||
}
|
||||
//Enable slimscroll for fixed layout
|
||||
if ($.AdminLTE.options.sidebarSlimScroll) {
|
||||
if (typeof $.fn.slimScroll != 'undefined') {
|
||||
//Destroy if it exists
|
||||
$(".sidebar").slimScroll({destroy: true}).height("auto");
|
||||
//Add slimscroll
|
||||
$(".sidebar").slimscroll({
|
||||
height: ($(window).height() - $(".main-header").height()) + "px",
|
||||
color: "rgba(0,0,0,0.2)",
|
||||
size: "3px"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* PushMenu()
|
||||
* ==========
|
||||
* Adds the push menu functionality to the sidebar.
|
||||
*
|
||||
* @type Function
|
||||
* @usage: $.AdminLTE.pushMenu("[data-toggle='offcanvas']")
|
||||
*/
|
||||
$.AdminLTE.pushMenu = {
|
||||
activate: function (toggleBtn) {
|
||||
//Get the screen sizes
|
||||
var screenSizes = $.AdminLTE.options.screenSizes;
|
||||
|
||||
//Enable sidebar toggle
|
||||
$(document).on('click', toggleBtn, function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
//Enable sidebar push menu
|
||||
if ($(window).width() > (screenSizes.sm - 1)) {
|
||||
if ($("body").hasClass('sidebar-collapse')) {
|
||||
$("body").removeClass('sidebar-collapse').trigger('expanded.pushMenu');
|
||||
} else {
|
||||
$("body").addClass('sidebar-collapse').trigger('collapsed.pushMenu');
|
||||
}
|
||||
}
|
||||
//Handle sidebar push menu for small screens
|
||||
else {
|
||||
if ($("body").hasClass('sidebar-open')) {
|
||||
$("body").removeClass('sidebar-open').removeClass('sidebar-collapse').trigger('collapsed.pushMenu');
|
||||
} else {
|
||||
$("body").addClass('sidebar-open').trigger('expanded.pushMenu');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(".content-wrapper").click(function () {
|
||||
//Enable hide menu when clicking on the content-wrapper on small screens
|
||||
if ($(window).width() <= (screenSizes.sm - 1) && $("body").hasClass("sidebar-open")) {
|
||||
$("body").removeClass('sidebar-open');
|
||||
}
|
||||
});
|
||||
|
||||
//Enable expand on hover for sidebar mini
|
||||
if ($.AdminLTE.options.sidebarExpandOnHover
|
||||
|| ($('body').hasClass('fixed')
|
||||
&& $('body').hasClass('sidebar-mini'))) {
|
||||
this.expandOnHover();
|
||||
}
|
||||
},
|
||||
expandOnHover: function () {
|
||||
var _this = this;
|
||||
var screenWidth = $.AdminLTE.options.screenSizes.sm - 1;
|
||||
//Expand sidebar on hover
|
||||
$('.main-sidebar').hover(function () {
|
||||
if ($('body').hasClass('sidebar-mini')
|
||||
&& $("body").hasClass('sidebar-collapse')
|
||||
&& $(window).width() > screenWidth) {
|
||||
_this.expand();
|
||||
}
|
||||
}, function () {
|
||||
if ($('body').hasClass('sidebar-mini')
|
||||
&& $('body').hasClass('sidebar-expanded-on-hover')
|
||||
&& $(window).width() > screenWidth) {
|
||||
_this.collapse();
|
||||
}
|
||||
});
|
||||
},
|
||||
expand: function () {
|
||||
$("body").removeClass('sidebar-collapse').addClass('sidebar-expanded-on-hover');
|
||||
},
|
||||
collapse: function () {
|
||||
if ($('body').hasClass('sidebar-expanded-on-hover')) {
|
||||
$('body').removeClass('sidebar-expanded-on-hover').addClass('sidebar-collapse');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Tree()
|
||||
* ======
|
||||
* Converts the sidebar into a multilevel
|
||||
* tree view menu.
|
||||
*
|
||||
* @type Function
|
||||
* @Usage: $.AdminLTE.tree('.sidebar')
|
||||
*/
|
||||
$.AdminLTE.tree = function (menu) {
|
||||
var _this = this;
|
||||
var animationSpeed = $.AdminLTE.options.animationSpeed;
|
||||
$(menu).on('click', 'li a', function (e) {
|
||||
//Get the clicked link and the next element
|
||||
var $this = $(this);
|
||||
var checkElement = $this.next();
|
||||
|
||||
//Check if the next element is a menu and is visible
|
||||
if ((checkElement.is('.treeview-menu')) && (checkElement.is(':visible')) && (!$('body').hasClass('sidebar-collapse'))) {
|
||||
//Close the menu
|
||||
checkElement.slideUp(animationSpeed, function () {
|
||||
checkElement.removeClass('menu-open');
|
||||
//Fix the layout in case the sidebar stretches over the height of the window
|
||||
//_this.layout.fix();
|
||||
});
|
||||
checkElement.parent("li").removeClass("active");
|
||||
}
|
||||
//If the menu is not visible
|
||||
else if ((checkElement.is('.treeview-menu')) && (!checkElement.is(':visible'))) {
|
||||
//Get the parent menu
|
||||
var parent = $this.parents('ul').first();
|
||||
//Close all open menus within the parent
|
||||
var ul = parent.find('ul:visible').slideUp(animationSpeed);
|
||||
//Remove the menu-open class from the parent
|
||||
ul.removeClass('menu-open');
|
||||
//Get the parent li
|
||||
var parent_li = $this.parent("li");
|
||||
|
||||
//Open the target menu and add the menu-open class
|
||||
checkElement.slideDown(animationSpeed, function () {
|
||||
//Add the class active to the parent li
|
||||
checkElement.addClass('menu-open');
|
||||
parent.find('li.active').removeClass('active');
|
||||
parent_li.addClass('active');
|
||||
//Fix the layout in case the sidebar stretches over the height of the window
|
||||
_this.layout.fix();
|
||||
});
|
||||
}
|
||||
//if this isn't a link, prevent the page from being redirected
|
||||
if (checkElement.is('.treeview-menu')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/* ControlSidebar
|
||||
* ==============
|
||||
* Adds functionality to the right sidebar
|
||||
*
|
||||
* @type Object
|
||||
* @usage $.AdminLTE.controlSidebar.activate(options)
|
||||
*/
|
||||
$.AdminLTE.controlSidebar = {
|
||||
//instantiate the object
|
||||
activate: function () {
|
||||
//Get the object
|
||||
var _this = this;
|
||||
//Update options
|
||||
var o = $.AdminLTE.options.controlSidebarOptions;
|
||||
//Get the sidebar
|
||||
var sidebar = $(o.selector);
|
||||
//The toggle button
|
||||
var btn = $(o.toggleBtnSelector);
|
||||
|
||||
//Listen to the click event
|
||||
btn.on('click', function (e) {
|
||||
e.preventDefault();
|
||||
//If the sidebar is not open
|
||||
if (!sidebar.hasClass('control-sidebar-open')
|
||||
&& !$('body').hasClass('control-sidebar-open')) {
|
||||
//Open the sidebar
|
||||
_this.open(sidebar, o.slide);
|
||||
} else {
|
||||
_this.close(sidebar, o.slide);
|
||||
}
|
||||
});
|
||||
|
||||
//If the body has a boxed layout, fix the sidebar bg position
|
||||
var bg = $(".control-sidebar-bg");
|
||||
_this._fix(bg);
|
||||
|
||||
//If the body has a fixed layout, make the control sidebar fixed
|
||||
if ($('body').hasClass('fixed')) {
|
||||
_this._fixForFixed(sidebar);
|
||||
} else {
|
||||
//If the content height is less than the sidebar's height, force max height
|
||||
if ($('.content-wrapper, .right-side').height() < sidebar.height()) {
|
||||
_this._fixForContent(sidebar);
|
||||
}
|
||||
}
|
||||
},
|
||||
//Open the control sidebar
|
||||
open: function (sidebar, slide) {
|
||||
//Slide over content
|
||||
if (slide) {
|
||||
sidebar.addClass('control-sidebar-open');
|
||||
} else {
|
||||
//Push the content by adding the open class to the body instead
|
||||
//of the sidebar itself
|
||||
$('body').addClass('control-sidebar-open');
|
||||
}
|
||||
},
|
||||
//Close the control sidebar
|
||||
close: function (sidebar, slide) {
|
||||
if (slide) {
|
||||
sidebar.removeClass('control-sidebar-open');
|
||||
} else {
|
||||
$('body').removeClass('control-sidebar-open');
|
||||
}
|
||||
},
|
||||
_fix: function (sidebar) {
|
||||
var _this = this;
|
||||
if ($("body").hasClass('layout-boxed')) {
|
||||
sidebar.css('position', 'absolute');
|
||||
sidebar.height($(".wrapper").height());
|
||||
$(window).resize(function () {
|
||||
_this._fix(sidebar);
|
||||
});
|
||||
} else {
|
||||
sidebar.css({
|
||||
'position': 'fixed',
|
||||
'height': 'auto'
|
||||
});
|
||||
}
|
||||
},
|
||||
_fixForFixed: function (sidebar) {
|
||||
sidebar.css({
|
||||
'position': 'fixed',
|
||||
'max-height': '100%',
|
||||
'overflow': 'auto',
|
||||
'padding-bottom': '50px'
|
||||
});
|
||||
},
|
||||
_fixForContent: function (sidebar) {
|
||||
$(".content-wrapper, .right-side").css('min-height', sidebar.height());
|
||||
}
|
||||
};
|
||||
|
||||
/* BoxWidget
|
||||
* =========
|
||||
* BoxWidget is a plugin to handle collapsing and
|
||||
* removing boxes from the screen.
|
||||
*
|
||||
* @type Object
|
||||
* @usage $.AdminLTE.boxWidget.activate()
|
||||
* Set all your options in the main $.AdminLTE.options object
|
||||
*/
|
||||
$.AdminLTE.boxWidget = {
|
||||
selectors: $.AdminLTE.options.boxWidgetOptions.boxWidgetSelectors,
|
||||
icons: $.AdminLTE.options.boxWidgetOptions.boxWidgetIcons,
|
||||
animationSpeed: $.AdminLTE.options.animationSpeed,
|
||||
activate: function (_box) {
|
||||
var _this = this;
|
||||
if (!_box) {
|
||||
_box = document; // activate all boxes per default
|
||||
}
|
||||
//Listen for collapse event triggers
|
||||
$(_box).on('click', _this.selectors.collapse, function (e) {
|
||||
e.preventDefault();
|
||||
_this.collapse($(this));
|
||||
});
|
||||
|
||||
//Listen for remove event triggers
|
||||
$(_box).on('click', _this.selectors.remove, function (e) {
|
||||
e.preventDefault();
|
||||
_this.remove($(this));
|
||||
});
|
||||
},
|
||||
collapse: function (element) {
|
||||
var _this = this;
|
||||
//Find the box parent
|
||||
var box = element.parents(".box").first();
|
||||
//Find the body and the footer
|
||||
var box_content = box.find("> .box-body, > .box-footer, > form >.box-body, > form > .box-footer");
|
||||
if (!box.hasClass("collapsed-box")) {
|
||||
//Convert minus into plus
|
||||
element.children(":first")
|
||||
.removeClass(_this.icons.collapse)
|
||||
.addClass(_this.icons.open);
|
||||
//Hide the content
|
||||
box_content.slideUp(_this.animationSpeed, function () {
|
||||
box.addClass("collapsed-box");
|
||||
});
|
||||
} else {
|
||||
//Convert plus into minus
|
||||
element.children(":first")
|
||||
.removeClass(_this.icons.open)
|
||||
.addClass(_this.icons.collapse);
|
||||
//Show the content
|
||||
box_content.slideDown(_this.animationSpeed, function () {
|
||||
box.removeClass("collapsed-box");
|
||||
});
|
||||
}
|
||||
},
|
||||
remove: function (element) {
|
||||
//Find the box parent
|
||||
var box = element.parents(".box").first();
|
||||
box.slideUp(this.animationSpeed);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* ------------------
|
||||
* - Custom Plugins -
|
||||
* ------------------
|
||||
* All custom plugins are defined below.
|
||||
*/
|
||||
|
||||
/*
|
||||
* BOX REFRESH BUTTON
|
||||
* ------------------
|
||||
* This is a custom plugin to use with the component BOX. It allows you to add
|
||||
* a refresh button to the box. It converts the box's state to a loading state.
|
||||
*
|
||||
* @type plugin
|
||||
* @usage $("#box-widget").boxRefresh( options );
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
"use strict";
|
||||
|
||||
$.fn.boxRefresh = function (options) {
|
||||
|
||||
// Render options
|
||||
var settings = $.extend({
|
||||
//Refresh button selector
|
||||
trigger: ".refresh-btn",
|
||||
//File source to be loaded (e.g: ajax/src.php)
|
||||
source: "",
|
||||
//Callbacks
|
||||
onLoadStart: function (box) {
|
||||
return box;
|
||||
}, //Right after the button has been clicked
|
||||
onLoadDone: function (box) {
|
||||
return box;
|
||||
} //When the source has been loaded
|
||||
|
||||
}, options);
|
||||
|
||||
//The overlay
|
||||
var overlay = $('<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>');
|
||||
|
||||
return this.each(function () {
|
||||
//if a source is specified
|
||||
if (settings.source === "") {
|
||||
if (window.console) {
|
||||
window.console.log("Please specify a source first - boxRefresh()");
|
||||
}
|
||||
return;
|
||||
}
|
||||
//the box
|
||||
var box = $(this);
|
||||
//the button
|
||||
var rBtn = box.find(settings.trigger).first();
|
||||
|
||||
//On trigger click
|
||||
rBtn.on('click', function (e) {
|
||||
e.preventDefault();
|
||||
//Add loading overlay
|
||||
start(box);
|
||||
|
||||
//Perform ajax call
|
||||
box.find(".box-body").load(settings.source, function () {
|
||||
done(box);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function start(box) {
|
||||
//Add overlay and loading img
|
||||
box.append(overlay);
|
||||
|
||||
settings.onLoadStart.call(box);
|
||||
}
|
||||
|
||||
function done(box) {
|
||||
//Remove overlay and loading img
|
||||
box.find(overlay).remove();
|
||||
|
||||
settings.onLoadDone.call(box);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
/*
|
||||
* EXPLICIT BOX CONTROLS
|
||||
* -----------------------
|
||||
* This is a custom plugin to use with the component BOX. It allows you to activate
|
||||
* a box inserted in the DOM after the app.js was loaded, toggle and remove box.
|
||||
*
|
||||
* @type plugin
|
||||
* @usage $("#box-widget").activateBox();
|
||||
* @usage $("#box-widget").toggleBox();
|
||||
* @usage $("#box-widget").removeBox();
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
'use strict';
|
||||
|
||||
$.fn.activateBox = function () {
|
||||
$.AdminLTE.boxWidget.activate(this);
|
||||
};
|
||||
|
||||
$.fn.toggleBox = function(){
|
||||
var button = $($.AdminLTE.boxWidget.selectors.collapse, this);
|
||||
$.AdminLTE.boxWidget.collapse(button);
|
||||
};
|
||||
|
||||
$.fn.removeBox = function(){
|
||||
var button = $($.AdminLTE.boxWidget.selectors.remove, this);
|
||||
$.AdminLTE.boxWidget.remove(button);
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
/*
|
||||
* TODO LIST CUSTOM PLUGIN
|
||||
* -----------------------
|
||||
* This plugin depends on iCheck plugin for checkbox and radio inputs
|
||||
*
|
||||
* @type plugin
|
||||
* @usage $("#todo-widget").todolist( options );
|
||||
*/
|
||||
(function ($) {
|
||||
|
||||
'use strict';
|
||||
|
||||
$.fn.todolist = function (options) {
|
||||
// Render options
|
||||
var settings = $.extend({
|
||||
//When the user checks the input
|
||||
onCheck: function (ele) {
|
||||
return ele;
|
||||
},
|
||||
//When the user unchecks the input
|
||||
onUncheck: function (ele) {
|
||||
return ele;
|
||||
}
|
||||
}, options);
|
||||
|
||||
return this.each(function () {
|
||||
|
||||
if (typeof $.fn.iCheck != 'undefined') {
|
||||
$('input', this).on('ifChecked', function () {
|
||||
var ele = $(this).parents("li").first();
|
||||
ele.toggleClass("done");
|
||||
settings.onCheck.call(ele);
|
||||
});
|
||||
|
||||
$('input', this).on('ifUnchecked', function () {
|
||||
var ele = $(this).parents("li").first();
|
||||
ele.toggleClass("done");
|
||||
settings.onUncheck.call(ele);
|
||||
});
|
||||
} else {
|
||||
$('input', this).on('change', function () {
|
||||
var ele = $(this).parents("li").first();
|
||||
ele.toggleClass("done");
|
||||
if ($('input', ele).is(":checked")) {
|
||||
settings.onCheck.call(ele);
|
||||
} else {
|
||||
settings.onUncheck.call(ele);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}(jQuery));
|
|
@ -1,8 +1,6 @@
|
|||
<html>
|
||||
{{>head}}
|
||||
<body>
|
||||
<div id="body_content">
|
||||
{{{ body }}}
|
||||
</div>
|
||||
<body clas="hold-transition skin-blue sidebar-mini" id="app-body">
|
||||
{{{ body }}}
|
||||
</body>
|
||||
</html>
|
|
@ -1 +1 @@
|
|||
<script>require("javascripts/app")(document.getElementById("wrapper"));</script>
|
||||
<script>require("javascripts/app")(document.getElementById("app-body"));</script>
|
Loading…
Reference in a new issue