rewrite: start implementing groups. Note angular-bootstrap 0.4.0 required for nested tabs
This commit is contained in:
@@ -1,12 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
The authentication controller (login & facebook)
|
||||
*/
|
||||
habitrpg
|
||||
|
||||
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', '$location',
|
||||
function($scope, $rootScope, Groups) {
|
||||
$scope.groups = Groups.query();
|
||||
$scope.party = true;
|
||||
}
|
||||
]);
|
||||
.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', '$location',
|
||||
function($scope, $rootScope, Groups) {
|
||||
$scope.groups = Groups.query();
|
||||
$scope.party = true;
|
||||
}
|
||||
])
|
||||
|
||||
.controller("GuildsCtrl", ['$scope', 'Groups',
|
||||
function($scope, Groups) {
|
||||
$scope.type = 'guild';
|
||||
$scope.text = 'Guild';
|
||||
}
|
||||
])
|
||||
|
||||
.controller("PartyCtrl", ['$scope', 'Groups',
|
||||
function($scope, Groups) {
|
||||
$scope.type = 'party';
|
||||
$scope.text = 'Party';
|
||||
Groups.query(function(groups){
|
||||
$scope.group = groups.party;
|
||||
})
|
||||
}
|
||||
])
|
||||
|
||||
.controller("TavernCtrl", ['$scope', 'Groups',
|
||||
function($scope, Groups) {
|
||||
//FIXME make sure this query is only called once for all these controllers! If not, let's memoize groups at groupServices level
|
||||
Groups.query(function(groups){
|
||||
$scope.group = groups.tavern;
|
||||
});
|
||||
}
|
||||
])
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
"angular": "1.2.0-rc.1",
|
||||
"angular-resource": "1.2.0-rc.1",
|
||||
"angular-ui": "~0.4.0",
|
||||
"angular-bootstrap": "~0.5.0",
|
||||
"angular-bootstrap": "0.4.0",
|
||||
"habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#rewrite",
|
||||
"lodash": "~1.3.1",
|
||||
"moment": "~2.1.0",
|
||||
|
||||
@@ -8,7 +8,7 @@ _ = require('lodash');
|
||||
|
||||
icalendar = require('icalendar');
|
||||
|
||||
api = require('./api');
|
||||
api = require('./user');
|
||||
|
||||
/* ---------- Deprecated Paths ------------*/
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// @see ../routes for routing
|
||||
|
||||
var _ = require('lodash');
|
||||
var nconf = require('nconf');
|
||||
var async = require('async');
|
||||
var algos = require('habitrpg-shared/script/algos');
|
||||
var helpers = require('habitrpg-shared/script/helpers');
|
||||
var items = require('habitrpg-shared/script/items');
|
||||
var User = require('./../models/user').model;
|
||||
var Group = require('./../models/group').model;
|
||||
var api = module.exports;
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------
|
||||
Party
|
||||
------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
api.getGroups = function(req, res, next) {
|
||||
var user = res.locals.user;
|
||||
/*TODO should we support non-authenticated users? just for viewing public groups?*/
|
||||
|
||||
return async.parallel({
|
||||
party: function(cb) {
|
||||
async.waterfall([
|
||||
function(cb2) {
|
||||
Group.findOne({type: 'party', members: {'$in': [user._id]}}, cb2);
|
||||
}, function(party, cb2) {
|
||||
var fields, query;
|
||||
party = party.toJSON();
|
||||
query = {_id: {
|
||||
'$in': party.members,
|
||||
'$nin': [user._id]
|
||||
}
|
||||
};
|
||||
fields = 'profile preferences items stats achievements party backer auth.local.username auth.facebook.first_name auth.facebook.last_name auth.facebook.name auth.facebook.username'.split(' ');
|
||||
fields = _.reduce(fields, (function(m, k, v) {m[k] = 1;return m;}), {});
|
||||
User.find(query, fields, function(err, members) {
|
||||
party.members = members;
|
||||
cb2(err, party);
|
||||
});
|
||||
}
|
||||
], function(err, members) {
|
||||
cb(err, members);
|
||||
});
|
||||
},
|
||||
guilds: function(cb) {
|
||||
Group.find({type: 'guild', members: {'$in': [user._id]}}, cb);
|
||||
},
|
||||
tavern: function(cb) {
|
||||
Group.findOne({_id: 'habitrpg'}, cb);
|
||||
},
|
||||
"public": function(cb) {
|
||||
Group.find({
|
||||
privacy: 'public'
|
||||
}, {
|
||||
name: 1,
|
||||
description: 1,
|
||||
members: 1
|
||||
}, cb);
|
||||
}
|
||||
}, function(err, results) {
|
||||
if (err) return res.json(500, {err: err});
|
||||
res.json(results);
|
||||
});
|
||||
};
|
||||
+39
-26
@@ -1,19 +1,21 @@
|
||||
var express = require('express');
|
||||
var router = new express.Router();
|
||||
var api = require('../controllers/api');
|
||||
var user = require('../controllers/user');
|
||||
var groups = require('../controllers/groups');
|
||||
|
||||
/*
|
||||
---------- /api/v1 API ------------
|
||||
Every url added to router is prefaced by /api/v1
|
||||
See ./routes/coffee for routes
|
||||
|
||||
v1 API. Requires x-api-user (user id) and x-api-key (api key) headers, Test with:
|
||||
v1 user. Requires x-api-user (user id) and x-api-key (api key) headers, Test with:
|
||||
$ cd node_modules/racer && npm install && cd ../..
|
||||
$ mocha test/api.mocha.coffee
|
||||
$ mocha test/user.mocha.coffee
|
||||
*/
|
||||
|
||||
var auth, cron, verifyTaskExists;
|
||||
auth = api.auth, verifyTaskExists = api.verifyTaskExists, cron = api.cron;
|
||||
var auth = user.auth
|
||||
var verifyTaskExists = user.verifyTaskExists
|
||||
var cron = user.cron;
|
||||
|
||||
router.get('/status', function(req, res) {
|
||||
return res.json({
|
||||
@@ -22,37 +24,48 @@ router.get('/status', function(req, res) {
|
||||
});
|
||||
|
||||
/* Auth*/
|
||||
router.post('/register', api.registerUser);
|
||||
router.post('/register', user.registerUser);
|
||||
|
||||
/* Scoring*/
|
||||
router.post('/user/task/:id/:direction', auth, cron, api.scoreTask);
|
||||
router.post('/user/tasks/:id/:direction', auth, cron, api.scoreTask);
|
||||
router.post('/user/task/:id/:direction', auth, cron, user.scoreTask);
|
||||
router.post('/user/tasks/:id/:direction', auth, cron, user.scoreTask);
|
||||
|
||||
/* Tasks*/
|
||||
router.get('/user/tasks', auth, cron, api.getTasks);
|
||||
router.get('/user/task/:id', auth, cron, api.getTask);
|
||||
router.put('/user/task/:id', auth, cron, verifyTaskExists, api.updateTask);
|
||||
router.post('/user/tasks', auth, cron, api.updateTasks);
|
||||
router["delete"]('/user/task/:id', auth, cron, verifyTaskExists, api.deleteTask);
|
||||
router.post('/user/task', auth, cron, api.createTask);
|
||||
router.put('/user/task/:id/sort', auth, cron, verifyTaskExists, api.sortTask);
|
||||
router.post('/user/clear-completed', auth, cron, api.clearCompleted);
|
||||
router.get('/user/tasks', auth, cron, user.getTasks);
|
||||
router.get('/user/task/:id', auth, cron, user.getTask);
|
||||
router.put('/user/task/:id', auth, cron, verifyTaskExists, user.updateTask);
|
||||
router.post('/user/tasks', auth, cron, user.updateTasks);
|
||||
router["delete"]('/user/task/:id', auth, cron, verifyTaskExists, user.deleteTask);
|
||||
router.post('/user/task', auth, cron, user.createTask);
|
||||
router.put('/user/task/:id/sort', auth, cron, verifyTaskExists, user.sortTask);
|
||||
router.post('/user/clear-completed', auth, cron, user.clearCompleted);
|
||||
|
||||
/* Items*/
|
||||
router.post('/user/buy/:type', auth, cron, api.buy);
|
||||
router.post('/user/buy/:type', auth, cron, user.buy);
|
||||
|
||||
/* User*/
|
||||
router.get('/user', auth, cron, api.getUser);
|
||||
router.post('/user/auth/local', api.loginLocal);
|
||||
router.post('/user/auth/facebook', api.loginFacebook);
|
||||
router.put('/user', auth, cron, api.updateUser);
|
||||
router.post('/user/revive', auth, cron, api.revive);
|
||||
router.post('/user/batch-update', auth, cron, api.batchUpdate);
|
||||
router.post('/user/reroll', auth, cron, api.reroll);
|
||||
router.post('/user/buy-gems', auth, api.buyGems);
|
||||
router.get('/user', auth, cron, user.getUser);
|
||||
router.post('/user/auth/local', user.loginLocal);
|
||||
router.post('/user/auth/facebook', user.loginFacebook);
|
||||
router.put('/user', auth, cron, user.updateUser);
|
||||
router.post('/user/revive', auth, cron, user.revive);
|
||||
router.post('/user/batch-update', auth, cron, user.batchUpdate);
|
||||
router.post('/user/reroll', auth, cron, user.reroll);
|
||||
router.post('/user/buy-gems', auth, user.buyGems);
|
||||
|
||||
/* Groups*/
|
||||
router.get('/groups', auth, api.getGroups);
|
||||
router.get('/groups', auth, groups.getGroups);
|
||||
//TODO:
|
||||
//GET /groups/:gid (get group)
|
||||
//POST /groups/:gid (create group)
|
||||
//PUT /groups/:gid (edit group)
|
||||
//DELETE /groups/:gid
|
||||
|
||||
//GET /groups/:gid/chat
|
||||
//POST /groups/:gid/chat
|
||||
//PUT /groups/:gid/chat/:messageId
|
||||
//DELETE /groups/:gid/chat/:messageId
|
||||
|
||||
|
||||
|
||||
module.exports = router;
|
||||
@@ -1,363 +0,0 @@
|
||||
<groups-pane:>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a data-toggle='tab' data-target="#groups-party">Party</a></li>
|
||||
<li><a data-toggle='tab' data-target="#groups-guilds">Guilds</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="groups-party">
|
||||
{#if _party.id}
|
||||
<app:groups:group group={groups[_party.id]} />
|
||||
{else if _user.invitations.party}
|
||||
<!-- #with required for the accept/reject buttons -->
|
||||
{#with _user.invitations.party as :party}
|
||||
<h2>You're Invited To {:party.name}</h2>
|
||||
<a class='btn btn-success' data-type='party' x-bind="click:acceptInvitation">Accept</a>
|
||||
<a class='btn btn-danger' x-bind="click:rejectInvitation">Reject</a>
|
||||
{/}
|
||||
{else}
|
||||
<h2>Create A Party</h2>
|
||||
<p>You are not in a party. You can either create one and invite friends, or if you want to join an existing party, have them enter:</p>
|
||||
<pre class=prettyprint>{_user.id}</pre>
|
||||
<app:groups:create-group type='party' />
|
||||
{/}
|
||||
</div>
|
||||
|
||||
<div class='tab-pane' id="groups-guilds">
|
||||
<ul class="nav nav-pills">
|
||||
<li class=active><a data-toggle='tab' data-target="#groups-guilds-public">Public Guilds</a></li>
|
||||
{{#each _guilds as :guild}}
|
||||
<li><a data-toggle='tab' data-target="#groups-guild-{{:guild.id}}">{:guild.name}</a></li>
|
||||
{{/}}
|
||||
<li><a data-toggle='tab' data-target="#groups-guild-create">Create Guild</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
|
||||
<div class='tab-pane active' id='groups-guilds-public'>
|
||||
<!-- strange bug here - derby paths supposed to work like _user?.invitations?.guilds, wtf? -->
|
||||
{#if and(_user.invitations,_user.invitations.guilds)}
|
||||
{#each _user.invitations.guilds as :invitation}
|
||||
<div>
|
||||
<h3>You're Invited To {:invitation.name}</h3>
|
||||
<a class='btn btn-success' data-type='guild' x-bind="click:acceptInvitation">Accept</a>
|
||||
<a class='btn btn-danger' x-bind="click:rejectInvitation">Reject</a>
|
||||
</div>
|
||||
{/}
|
||||
{/}
|
||||
<app:groups:public-groups />
|
||||
</div>
|
||||
|
||||
{{#each _guilds as :guild}}
|
||||
<div class="tab-pane" id="groups-guild-{{:guild.id}}" >
|
||||
<app:groups:group group={:guild} />
|
||||
</div>
|
||||
{{/}}
|
||||
|
||||
<div class='tab-pane' id='groups-guild-create'>
|
||||
<app:groups:create-group type='guild' />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<public-groups:>
|
||||
<table class="table table-striped">
|
||||
{#each _publicGroups as :public}
|
||||
<tr><td>
|
||||
<ul class="pull-right challenge-accordion-header-specs">
|
||||
<li>{count(:public.members)} member(s)</li>
|
||||
<li>
|
||||
<!-- join / leave -->
|
||||
{#if indexOf(:public.members,_user.id)}
|
||||
<a x-bind="click:groupLeave" data-id={{:public.id}} class='btn btn-small btn-danger'><i class='icon-ban-circle'></i> Leave</a>
|
||||
{else}
|
||||
<a x-bind="click:joinGroup" class='btn btn-small btn-success'><i class='icon-ok'></i> Join</a>
|
||||
{/}
|
||||
</li>
|
||||
</ul>
|
||||
<h4>{:public.name}</h4>
|
||||
<p>{:public.description}</p>
|
||||
</td></tr>
|
||||
{/}
|
||||
</table>
|
||||
|
||||
<create-group:>
|
||||
<form class=form-horizontal x-bind="submit:groupCreate" data-type={{@type}} >
|
||||
{#if _groupError}
|
||||
<div class='alert alert-danger'>{_groupError}</div>
|
||||
{/}
|
||||
<div class="control-group whatever-options">
|
||||
<div class=control-group>
|
||||
<label class="control-label" for="new-group-name">{{#if equal(@type,'party')}}Party{{else}}Guild{{/}} Name</label>
|
||||
<div class="controls">
|
||||
<input required id=new-group-name type=text class="input-medium option-content" placeholder="{{#if equal(@type,'party')}}Party{{else}}Guild{{/}} Name" value="{_new.group.name}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class=control-group>
|
||||
<label class="control-label" for="new-group-description">Description</label>
|
||||
<div class="controls">
|
||||
<textarea id=new-group-description cols=3 class='option-content' placeholder='Description'>{_new.group.description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if equal(@type,'guild')}}
|
||||
<div class=control-group>
|
||||
<div class=controls>
|
||||
<label class="radio">
|
||||
<input type='radio' name='new-group-privacy' checked="{equal('public',_new.group.privacy)}" > Public
|
||||
</label>
|
||||
<label class="radio">
|
||||
<input type='radio' name='new-group-privacy' checked="{equal('private',_new.group.privacy)}" > Invite Only
|
||||
</label>
|
||||
<input type="submit" class="btn {#unless and(_new.group.privacy,_new.group.name)}disabled{/}" value="Create" /><span class='gem-cost'>4 Gems</span>
|
||||
<p><small>The Gem cost promotes high quality guilds, and is transferred into your guild's bank for use as rewards in the upcoming Challenges feature!</small></p>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class=control-group>
|
||||
<div class=controls>
|
||||
<input type="submit" class="btn " value="Create" />
|
||||
</div>
|
||||
</div>
|
||||
{{/}}
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<group:>
|
||||
{{#if and(equal(@group.type,'guild'),not(equal(@group.id,'habitrpg')))}}
|
||||
<a class="pull-right gem-wallet" rel="popover" data-trigger="hover" data-title="Guild Bank" data-content="Gems which your Guild leader can use for prizes in the upcoming <a target=_blank href='https://trello.com/card/challenges-individual-party-guild-public/50e5d3684fe3a7266b0036d6/58'>Challenges</a> feature." data-placement="bottom" data-html=true>
|
||||
<!--<span class="task-action-btn tile flush bright add-gems-btn">+</span>-->
|
||||
<span class="task-action-btn tile flush neutral"><div class="Gems"></div>{{gems(@group.balance)}} Guild Gems</span>
|
||||
</a>
|
||||
{{/}}
|
||||
<div class='row-fluid'>
|
||||
<div class='span4'>
|
||||
{{#if equal(@group.id,'habitrpg')}}
|
||||
<div class='tavern-pane'>
|
||||
<table><tr>
|
||||
<td><div class='NPC-Daniel'></div></td>
|
||||
<td>
|
||||
<div class="popover static-popover fade right in">
|
||||
<div class="arrow"></div>
|
||||
<h3 class="popover-title">Daniel Johansson</h3>
|
||||
<div class="popover-content">
|
||||
Welcome to the Tavern! I'm <a target="_blank" href="http://www.kickstarter.com/profile/2014640723">Daniel</a>, the bar keep. If you want to rest a while (going on vacation? sudden illness?), I'll set you up at the inn - dailies won't hurt you while you're resting. Stay a while & meet the locals.
|
||||
<div><button x-bind="click:toggleResting" class='btn btn-large btn-success {#if _user.flags.rest}active{/}'>{#if _user.flags.rest}Check Out of Inn{else}Rest In The Inn{/}</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr></table>
|
||||
</div>
|
||||
<div class='alert alert-info {#unless _user.flags.rest}hidden{/}'>Whilst resting, your dailies are saved and aren't affected by day turn-over. Whether you check out tomorrow or in a week's time, you'll continue in the same state as when you checked in.</div>
|
||||
|
||||
<div class=well>
|
||||
<h3>Resources</h3>
|
||||
<ul class=unstyled>
|
||||
<li><h4><a target="_blank" href="http://community.habitrpg.com/forums/lfg">LFG Posts</a></h4></li>
|
||||
<li><h4><a target="_blank" href="http://www.youtube.com/watch?feature=player_embedded&v=cT5ghzZFfao">Tutorial</a></h4></li>
|
||||
<li><h4><a target="_blank" href="http://community.habitrpg.com/faq-page">FAQ</a></h4></li>
|
||||
<li><h4><a target="_blank" href="http://community.habitrpg.com/node/280">Report a Problem</a></h4></li>
|
||||
<li><h4><a target="_blank" href="https://trello.com/board/habitrpg/50e5d3684fe3a7266b0036d6">Request a Feature</a></h4></li>
|
||||
<li><h4><a target="_blank" href="http://community.habitrpg.com/forum">Community Forum</a></h4></li>
|
||||
</ul>
|
||||
</div>
|
||||
{{else}}
|
||||
<h3>{@group.name}</h3>
|
||||
<div class="accordion" id="accordion-{{@group.id}}-parent">
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion-{{@group.id}}-parent" href="#accordion-{{@group.id}}-information">Information</a>
|
||||
</div>
|
||||
<div id="accordion-{{@group.id}}-information" class="accordion-body collapse in">
|
||||
<div class="accordion-inner blah-options">
|
||||
{#if _editing.groups[@group.id]}
|
||||
<div style="height:10px">
|
||||
<a class=pull-right x-bind=click:toggleGroupEdit data-gid={{@group.id}} ><i class=icon-ok></i></a>
|
||||
</div>
|
||||
<input type=text value={@group.name} class='option-content' placeholder='Group Name' />
|
||||
<textarea cols=3 placeholder='Description'>{@group.description}</textarea>
|
||||
<input type=url class=option-content placeholder="Logo Url" value={@group.logo} />
|
||||
{#with @group}
|
||||
<form class='form-inline' x-bind="submit:groupAddWebsite" >
|
||||
<input type=url placeholder='Website' class='option-content' value={_newGroupWebsite} />
|
||||
<input type=submit value="Add" />
|
||||
</form>
|
||||
<h4>Assign Group Leader</h4>
|
||||
<select id=group-leader-selection>
|
||||
{#each @group.members as :memberId}
|
||||
<option selected="{equal(:memberId,_new.groupLeader)}">{{username(_members[:memberId].auth,_members[:memberId].profile.name)}}</option>
|
||||
{/}
|
||||
</select>
|
||||
<button x-bind=click:assignGroupLeader >Assign</button>
|
||||
|
||||
{/}
|
||||
{#if @group.websites}
|
||||
<h4>Resources</h4>
|
||||
<ul class=unstyled>
|
||||
{#each @group.websites as :website}
|
||||
<li><a x-bind='click:removeAt'><i class='icon-trash'></i></a> <a target="_blank" href="{:website}" >{:website}</a></li>
|
||||
{/}
|
||||
</ul>
|
||||
{/}
|
||||
{else}
|
||||
{#if @group.logo}<img class=pull-right style='max-width:150px' src={@group.logo} />{/}
|
||||
{{#if equal(@group.leader,_user.id)}}
|
||||
<a class=pull-right x-bind=click:toggleGroupEdit data-gid={{@group.id}} ><i class=icon-pencil></i></a>
|
||||
{{/}}
|
||||
<div>{@group.description}</div>
|
||||
{#if @group.websites}
|
||||
<h4>Resources</h4>
|
||||
<ul class=unstyled>
|
||||
{#each @group.websites as :website}
|
||||
<li><a target="_blank" href="{:website}">{:website}</a></li>
|
||||
{/}
|
||||
</ul>
|
||||
{/}
|
||||
{/}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion-{{@group.id}}-parent" href="#accordion-{{@group.id}}-members">Members</a>
|
||||
</div>
|
||||
<div id="accordion-{{@group.id}}-members" class="accordion-body collapse">
|
||||
<div class="accordion-inner">
|
||||
<table class="table table-striped">
|
||||
{#each @group.members as :memberId}
|
||||
<tr><td>
|
||||
<!-- allow leaders to ban members -->
|
||||
{{#if and(equal(@group.leader,_user.id),not(equal(_user.id,:memberId)))}}
|
||||
{{#with @group.members[$index]}}
|
||||
<a x-bind=click:removeAt data-refresh=true data-confirm='Boot this member?'>
|
||||
<i class=icon-ban-circle rel=tooltip title="Boot Member"></i>
|
||||
</a>
|
||||
{{/}}
|
||||
|
||||
{{/}}
|
||||
<a data-toggle='modal' data-target="#avatar-modal-{{:memberId}}">
|
||||
<span class="{{#if equal(@group.leader,:memberId)}}badge badge-info{{/}}">
|
||||
{{username(_members[:memberId].auth, _members[:memberId].profile.name)}}
|
||||
</span>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
({{:memberId}})
|
||||
</td>
|
||||
</tr>
|
||||
{/}
|
||||
</table>
|
||||
{#with @group as :group}
|
||||
<form class="form-inline" x-bind="submit:groupInvite" data-type="{@group.type}" >
|
||||
{#if _groupError}
|
||||
<div class='alert alert-danger'>{_groupError}</div>
|
||||
{/}
|
||||
<div class='control-group'>
|
||||
<input type="text" class="input-medium" placeholder="User Id" value="{_groupInvitee}">
|
||||
<input type="submit" class="btn" value="Invite" />
|
||||
</div>
|
||||
</form>
|
||||
{/}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a class="accordion-toggle" data-toggle="collapse" data-parent="#accordion-{{@group.id}}-parent" href="#accordion-{{@group.id}}-challenges">Challenges</a>
|
||||
</div>
|
||||
<div id="accordion-{{@group.id}}-challenges" class="accordion-body collapse">
|
||||
<div class="accordion-inner">
|
||||
<span class=label><i class=icon-bullhorn></i> Challenges</span> coming soon! <a target="_blank" href="https://trello.com/card/challenges-individual-party-guild-public/50e5d3684fe3a7266b0036d6/58">Details</a>
|
||||
<!--{#if @group.challenges}
|
||||
<table class="table table-striped">
|
||||
{#each @group.challenges as :challenge}
|
||||
<tr><td>
|
||||
{:challenge.name}
|
||||
</td></tr>
|
||||
{/}
|
||||
</table>
|
||||
Visit the <span class=label><i class=icon-bullhorn></i> Challenges</span> for more information.
|
||||
{else}
|
||||
No challenges yet, visit the <span class=label><i class=icon-bullhorn></i> Challenges</span> tab to create one.
|
||||
{/}-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<a class='btn btn-danger' data-id="{{@group.id}}" x-bind="click:groupLeave">Leave</a>
|
||||
{{/}}
|
||||
|
||||
</div>
|
||||
<div class='span8'>
|
||||
|
||||
{{#if equal(@group.id,'habitrpg')}}
|
||||
<h3>Tavern Talk & LFG</h3>
|
||||
<div class='row-fluid'>
|
||||
<div class='span3'>
|
||||
<ul class='unstyled buttonList'>
|
||||
<li><a class='btn btn-info' style='width:100%' target="_blank" href="http://community.habitrpg.com/faq-page">FAQ</a></li>
|
||||
<li><a class='btn btn-info' style='width:100%' target="_blank" href="http://community.habitrpg.com/node/280">Report a Problem</a></li>
|
||||
<li><a class='btn btn-info' style='width:100%' target="_blank" href="https://trello.com/board/habitrpg/50e5d3684fe3a7266b0036d6">Request a Feature</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class=span9>
|
||||
<app:groups:chat-box group={@group} />
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{#if equal(@group.leader,_user.id)}}
|
||||
{#if _editing.leaderMessage[@group.id]}
|
||||
<a x-bind=click:toggleLeaderMessageEdit data-gid={{@group.id}} class=pull-right><i class=icon-ok></i></a>
|
||||
<textarea cols=3 placeholder='Message from group leader'>{@group.leaderMessage}</textarea>
|
||||
{else}
|
||||
<a x-bind=click:toggleLeaderMessageEdit data-gid={{@group.id}} class='btn pull-right'>Edit leader message</a>
|
||||
{/}
|
||||
{{/}}
|
||||
{#if @group.leaderMessage}
|
||||
<table><tr>
|
||||
<td><app:avatar:avatar profile="{{_members[@group.leader]}}" /></td>
|
||||
<td>
|
||||
<div class="popover static-popover fade right in">
|
||||
<div class="arrow"></div>
|
||||
<h3 class="popover-title">{{username(_members[@group.leader].auth,_members[@group.leader].profile.name)}}</h3>
|
||||
<div class="popover-content">{@group.leaderMessage}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr></table>
|
||||
{/}
|
||||
<h3>Chat</h3>
|
||||
<app:groups:chat-box group={@group} />
|
||||
{{/}}
|
||||
|
||||
<ul class='unstyled tavern-chat'>
|
||||
{#each @group.chat as :message}
|
||||
<app:groups:chat-message message={{:message}} />
|
||||
{/}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<chat-box:>
|
||||
{{#with @group as :group}}
|
||||
<form x-bind='submit:sendChat'>
|
||||
<textarea class="span6" rows="3" x-bind='keyup:chatKeyup'>{_chatMessage}</textarea><br/>
|
||||
<input class=btn type=submit value="Send Chat" />
|
||||
</form>
|
||||
{{/}}
|
||||
|
||||
<chat-message:>
|
||||
<li class="{{#if indexOf(:message.text, username(_user.auth, _user.profile.name))}}highlight{{/if}}">
|
||||
<span
|
||||
class="label {{#if @message.npc}}label-success{{else if @message.contributor}}label-inverse{{else if equal(@message.uuid,_user.id)}}label-info{{/}} chat-message"
|
||||
rel='tooltip' title="{{@message.contributor}}{{@message.npc}}">
|
||||
{{@message.user}}</span> {{@message.text}} - <span class='muted time'>{relativeDate(@message.timestamp, _currentTime)}
|
||||
{{#if or(_user.backer.admin,equal(@message.uuid,_user.id))}}{{#with @message}}<a x-bind="click:deleteChatMessage"><i rel=tooltip title=Delete class=icon-remove></i></a>{{/}}{{/}}
|
||||
</span>
|
||||
</li>
|
||||
@@ -0,0 +1,4 @@
|
||||
form(x-bind='submit:sendChat')
|
||||
textarea.span6(rows='3', x-bind='keyup:chatKeyup') {{_chatMessage}}
|
||||
br
|
||||
input.btn(type='submit', value='Send Chat')
|
||||
@@ -0,0 +1,8 @@
|
||||
li(ng-repeat='message in group.chat', ng-class='{highlight: indexOf(message.text,username(user.auth,user.profile.name))}')
|
||||
span.label.chat-message(ng-class='{"label-success": message.npc, "label-inverse": message.contributor, "label-info": message.uuid == user.id}', tooltip='{{message.contributor}}{{message.npc}}')
|
||||
| {{message.user}}
|
||||
| {{message.text}} -
|
||||
span.muted.time
|
||||
| {{relativeDate(message.timestamp, _currentTime)}}
|
||||
a(ng-show='user.backer.admin || message.uuid == user.id', x-bind='click:deleteChatMessage')
|
||||
i.icon-remove(tooltip='Delete')
|
||||
@@ -0,0 +1,27 @@
|
||||
form.form-horizontal(x-bind='submit:groupCreate', data-type='{{type}}')
|
||||
.alert.alert-danger(ng-show='_groupError') {{_groupError}}
|
||||
.control-group.whatever-options
|
||||
.control-group
|
||||
label.control-label(for='new-group-name') {{text}} Name
|
||||
.controls
|
||||
input#new-group-name.input-medium.option-content(required, type='text', placeholder='{{text}} Name', value='{{_new.group.name}}')
|
||||
.control-group
|
||||
label.control-label(for='new-group-description') Description
|
||||
.controls
|
||||
textarea#new-group-description.option-content(cols='3', placeholder='Description') {{_new.group.description}}
|
||||
.control-group(ng-show='type=="guild"')
|
||||
.controls
|
||||
label.radio
|
||||
input(type='radio', name='new-group-privacy', checked='{{"public"==_new.group.privacy}}')
|
||||
| Public
|
||||
label.radio
|
||||
input(type='radio', name='new-group-privacy', checked='{{"private"==_new.group.privacy}}')
|
||||
| Invite Only
|
||||
input.btn(type='submit', ng-disabled='!_new.group.privacy && !_new.group.name', value='Create')
|
||||
span.gem-cost 4 Gems
|
||||
p
|
||||
small
|
||||
| The Gem cost promotes high quality guilds, and is transferred into your guild's bank for use as rewards in the upcoming Challenges feature!
|
||||
.control-group(ng-show='type=="party"')
|
||||
.controls
|
||||
input.btn(type='submit', value='Create')
|
||||
@@ -0,0 +1,108 @@
|
||||
a.pull-right.gem-wallet(ng-show='group.type=="guild" && group.id!="habitrpg"', rel='popover', data-trigger='hover', data-title='Guild Bank', data-content='Gems which your Guild leader can use for prizes in the upcoming <a target=_blank href="https://trello.com/card/challenges-individual-party-guild-public/50e5d3684fe3a7266b0036d6/58">Challenges</a> feature.', data-placement='bottom', data-html='true')
|
||||
// <span class="task-action-btn tile flush bright add-gems-btn">+</span>
|
||||
span.task-action-btn.tile.flush.neutral
|
||||
.Gems
|
||||
| {{gems(group.balance)}} Guild Gems
|
||||
.row-fluid
|
||||
.span4
|
||||
h3 {{group.name}}
|
||||
accordion
|
||||
accordion-group(heading='Information')
|
||||
.blah-options
|
||||
div(ng-show='_editing.groups[group.id]')
|
||||
div(style='height:10px')
|
||||
a.pull-right(x-bind='click:toggleGroupEdit', data-gid='{{group.id}}')
|
||||
i.icon-ok
|
||||
input.option-content(type='text', value='{group.name}', placeholder='Group Name')
|
||||
textarea(cols='3', placeholder='Description') {{group.description}}
|
||||
input.option-content(type='url', placeholder='Logo Url', value='{group.logo}')
|
||||
form.form-inline(x-bind='submit:groupAddWebsite')
|
||||
input.option-content(type='url', placeholder='Website', value='{_newGroupWebsite}')
|
||||
input(type='submit', value='Add')
|
||||
h4 Assign Group Leader
|
||||
select#group-leader-selection
|
||||
option(ng-repeat='memberId in group.members', selected='{equal(memberId,_new.groupLeader)}') {{username(_members[memberId].auth,_members[memberId].profile.name)}}
|
||||
button(x-bind='click:assignGroupLeader') Assign
|
||||
div(ng-show='group.websites')
|
||||
h4 Resources
|
||||
ul.unstyled
|
||||
li
|
||||
a(ng-repeat='website in group.websites', x-bind='click:removeAt')
|
||||
i.icon-trash
|
||||
a(target='_blank', href='{website}') {{website}}
|
||||
div(ng-show='!_editing.groups[group.id]')
|
||||
img.pull-right(ng-show='group.logo', style='max-width:150px', src='{group.logo}')
|
||||
a.pull-right(ng-if='group.leader==user.id', x-bind='click:toggleGroupEdit', data-gid='{{group.id}}')
|
||||
i.icon-pencil
|
||||
div {{group.description}}
|
||||
div(ng-show='group.websites')
|
||||
h4 Resources
|
||||
ul.unstyled
|
||||
li(ng-repeat='website in group.websites')
|
||||
a(target='_blank', ng-href='{{website}}') {{website}}
|
||||
|
||||
accordion-group(heading='Members')
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='memberId in group.members')
|
||||
td
|
||||
// allow leaders to ban members
|
||||
div(ng-show='and(equal(group.leader,_user.id),not(equal(_user.id,memberId)))')
|
||||
// {{#with group.members[$index]}}
|
||||
a(x-bind='click:removeAt', data-refresh='true', data-confirm='Boot this member?')
|
||||
i.icon-ban-circle(rel='tooltip', title='Boot Member')
|
||||
// {{/}}
|
||||
a(data-toggle='modal', data-target='#avatar-modal-{{memberId}}')
|
||||
span(ng-class='{"badge badge-info": group.leader==memberId}')
|
||||
| {{username(_members[memberId].auth, _members[memberId].profile.name)}}
|
||||
td
|
||||
| ({{memberId}})
|
||||
// {#with group as :group}
|
||||
form.form-inline(x-bind='submit:groupInvite', data-type='{group.type}')
|
||||
.alert.alert-danger(ng-show='_groupError') {_groupError}
|
||||
.control-group
|
||||
input.input-medium(type='text', placeholder='User Id', value='{_groupInvitee}')
|
||||
input.btn(type='submit', value='Invite')
|
||||
// {/}
|
||||
|
||||
//-accordion-group(heading='Challenges')
|
||||
span.label
|
||||
i.icon-bullhorn
|
||||
| Challenges
|
||||
| coming soon!
|
||||
a(target='_blank', href='https://trello.com/card/challenges-individual-party-guild-public/50e5d3684fe3a7266b0036d6/58') Details
|
||||
//-{#if group.challenges}
|
||||
//- <table class="table table-striped">
|
||||
//- {#each group.challenges as :challenge}
|
||||
//- <tr><td>
|
||||
//- {:challenge.name}
|
||||
//- </td></tr>
|
||||
//- {/}
|
||||
//- </table>
|
||||
//- Visit the <span class=label><i class=icon-bullhorn></i> Challenges</span> for more information.
|
||||
//-{else}
|
||||
//- No challenges yet, visit the <span class=label><i class=icon-bullhorn></i> Challenges</span> tab to create one.
|
||||
//-{/}
|
||||
a.btn.btn-danger(data-id='{{group.id}}', x-bind='click:groupLeave') Leave
|
||||
|
||||
.span8
|
||||
div(ng-if='group.leader==user.id')
|
||||
div(ng-show='_editing.leaderMessage[group.id]')
|
||||
a.pull-right(x-bind='click:toggleLeaderMessageEdit', data-gid='{{group.id}}')
|
||||
i.icon-ok
|
||||
textarea(cols='3', placeholder='Message from group leader') {group.leaderMessage}
|
||||
div(ng-hide='_editing.leaderMessage[group.id]')
|
||||
a.btn.pull-right(x-bind='click:toggleLeaderMessageEdit', data-gid='{{group.id}}') Edit leader message
|
||||
table(ng-show='group.leaderMessage')
|
||||
tr
|
||||
td
|
||||
app:avatar:avatar(profile='{{_members[group.leader]}}')
|
||||
td
|
||||
.popover.static-popover.fade.right.in
|
||||
.arrow
|
||||
h3.popover-title {{username(_members[group.leader].auth,_members[group.leader].profile.name)}}
|
||||
.popover-content {group.leaderMessage}
|
||||
h3 Chat
|
||||
include ./chat-box
|
||||
|
||||
ul.unstyled.tavern-chat
|
||||
include ./chat-message
|
||||
@@ -0,0 +1,52 @@
|
||||
div(ng-controller='GroupsCtrl')
|
||||
h4.alert.alert-warning Coming Soon! (Presently Incomplete & Read-Only)
|
||||
tabset
|
||||
tab(heading='Party')
|
||||
div(ng-show='groups.party.id', ng-controller='PartyCtrl')
|
||||
app:groups:group(group='{groups[_party.id]}')
|
||||
div(ng-hide='groups.party.id')
|
||||
div(ng-show='user.invitations.party')
|
||||
// #with required for the accept/reject buttons
|
||||
// {#with _user.invitations.party as :party}
|
||||
h2 You're Invited To {{party.name}}
|
||||
a.btn.btn-success(data-type='party', x-bind='click:acceptInvitation') Accept
|
||||
a.btn.btn-danger(x-bind='click:rejectInvitation') Reject
|
||||
// {/}
|
||||
div(ng-hide='user.invitations.party', ng-controller='PartyCtrl')
|
||||
h2 Create A Party
|
||||
p
|
||||
| You are not in a party. You can either create one and invite friends, or if you want to join an existing party, have them enter:
|
||||
pre.prettyprint.
|
||||
{{user.id}}
|
||||
include ./create-group
|
||||
|
||||
tab(heading='Guilds')
|
||||
tabset
|
||||
tab(heading='Public Guilds')
|
||||
div(ng-repeat='invitation in user.invitations.guilds')
|
||||
h3 You're Invited To {{invitation.name}}
|
||||
a.btn.btn-success(data-type='guild', x-bind='click:acceptInvitation') Accept
|
||||
a.btn.btn-danger(x-bind='click:rejectInvitation') Reject
|
||||
// Public Groups
|
||||
table.table.table-striped
|
||||
tr(ng-repeat='group in groups.public')
|
||||
td
|
||||
ul.pull-right.challenge-accordion-header-specs
|
||||
li {{count(group.members)}} member(s)
|
||||
li
|
||||
// join / leave
|
||||
a.btn.btn-small.btn-danger(ng-show='indexOf(group.members,user.id)', x-bind='click:groupLeave', data-id='{{group.id}}')
|
||||
i.icon-ban-circle
|
||||
| Leave
|
||||
a.btn.btn-small.btn-success(ng-hide='indexOf(group.members,user.id)', x-bind='click:joinGroup')
|
||||
i.icon-ok
|
||||
| Join
|
||||
h4 {{group.name}}
|
||||
p {{group.description}}
|
||||
|
||||
tab(ng-repeat='group in groups.guilds', heading='{{group.name}}')
|
||||
include ./group
|
||||
|
||||
tab(heading='Create Guild')
|
||||
div(ng-controller='GuildCtrl')
|
||||
include ./group
|
||||
@@ -0,0 +1,58 @@
|
||||
h4.alert.alert-warning Coming Soon! (Presently Incomplete & Read-Only)
|
||||
.row-fluid(ng-controller='TavernCtrl')
|
||||
.span4
|
||||
.tavern-pane
|
||||
table
|
||||
tr
|
||||
td
|
||||
.NPC-Daniel
|
||||
td
|
||||
.popover.static-popover.fade.right.in
|
||||
.arrow
|
||||
h3.popover-title Daniel Johansson
|
||||
.popover-content
|
||||
| Welcome to the Tavern! I'm
|
||||
a(target='_blank', href='http://www.kickstarter.com/profile/2014640723') Daniel
|
||||
| , the bar keep. If you want to rest a while (going on vacation? sudden illness?), I'll set you up at the inn - dailies won't hurt you while you're resting. Stay a while & meet the locals.
|
||||
div
|
||||
button.btn.btn-large.btn-success(ng-class='{active: user.flags.rest}',x-bind='click:toggleResting')
|
||||
span(ng-show='user.flags.rest') Check Out of Inn
|
||||
span(ng-hide='user.flags.rest') Rest In The Inn
|
||||
.alert.alert-info(ng-hide='user.flags.rest')
|
||||
| Whilst resting, your dailies are saved and aren't affected by day turn-over. Whether you check out tomorrow or in a week's time, you'll continue in the same state as when you checked in.
|
||||
.well
|
||||
h3 Resources
|
||||
ul.unstyled
|
||||
li
|
||||
h4
|
||||
a(target='_blank', href='http://community.habitrpg.com/forums/lfg') LFG Posts
|
||||
li
|
||||
h4
|
||||
a(target='_blank', href='http://www.youtube.com/watch?feature=player_embedded&v=cT5ghzZFfao') Tutorial
|
||||
li
|
||||
h4
|
||||
a(target='_blank', href='http://community.habitrpg.com/faq-page') FAQ
|
||||
li
|
||||
h4
|
||||
a(target='_blank', href='http://community.habitrpg.com/node/280') Report a Problem
|
||||
li
|
||||
h4
|
||||
a(target='_blank', href='https://trello.com/board/habitrpg/50e5d3684fe3a7266b0036d6') Request a Feature
|
||||
li
|
||||
h4
|
||||
a(target='_blank', href='http://community.habitrpg.com/forum') Community Forum
|
||||
.span8
|
||||
h3 Tavern Talk & LFG
|
||||
.row-fluid
|
||||
.span3
|
||||
ul.unstyled.buttonList
|
||||
li
|
||||
a.btn.btn-info(style='width:100%', target='_blank', href='http://community.habitrpg.com/faq-page') FAQ
|
||||
li
|
||||
a.btn.btn-info(style='width:100%', target='_blank', href='http://community.habitrpg.com/node/280') Report a Problem
|
||||
li
|
||||
a.btn.btn-info(style='width:100%', target='_blank', href='https://trello.com/board/habitrpg/50e5d3684fe3a7266b0036d6') Request a Feature
|
||||
.span9
|
||||
include ./chat-box
|
||||
ul.unstyled.tavern-chat
|
||||
include ./chat-message
|
||||
@@ -10,13 +10,13 @@
|
||||
| Profile
|
||||
include ./profile
|
||||
|
||||
//-tab
|
||||
tab
|
||||
tab-heading
|
||||
i.icon-heart
|
||||
| Groups
|
||||
app:groups:groups-pane
|
||||
include ./groups/index
|
||||
|
||||
tab(ng-show='user.flags.dropsEnabled')
|
||||
//-tab(ng-show='user.flags.dropsEnabled')
|
||||
tab-heading
|
||||
i.icon-gift
|
||||
| Inventory
|
||||
@@ -28,17 +28,17 @@
|
||||
h2 Market
|
||||
app:game-pane:market
|
||||
|
||||
tab(ng-show='user.flags.dropsEnabled')
|
||||
//-tab(ng-show='user.flags.dropsEnabled')
|
||||
tab-heading
|
||||
i.icon-leaf
|
||||
| Stable
|
||||
app:pets:stable
|
||||
|
||||
//-tab
|
||||
tab
|
||||
tab-heading
|
||||
i.icon-eye-close
|
||||
| Tavern
|
||||
app:groups:group(group='{_habitRPG}')
|
||||
include ./groups/tavern
|
||||
|
||||
tab
|
||||
tab-heading
|
||||
|
||||
Reference in New Issue
Block a user