mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
[#1465] add member modals back in. Not all info is present, just a bit more
work. Can now click guild & tavern members! does lazy-loading of members so we don't have to load all their information at once
This commit is contained in:
@@ -38,13 +38,13 @@ module.exports = function(grunt) {
|
|||||||
'public/js/services/sharedServices.js',
|
'public/js/services/sharedServices.js',
|
||||||
'public/js/services/userServices.js',
|
'public/js/services/userServices.js',
|
||||||
'public/js/services/groupServices.js',
|
'public/js/services/groupServices.js',
|
||||||
|
'public/js/services/memberServices.js',
|
||||||
|
|
||||||
'public/js/filters/filters.js',
|
'public/js/filters/filters.js',
|
||||||
|
|
||||||
'public/js/directives/directives.js',
|
'public/js/directives/directives.js',
|
||||||
|
|
||||||
'public/js/controllers/authCtrl.js',
|
'public/js/controllers/authCtrl.js',
|
||||||
'public/js/controllers/characterCtrl.js',
|
|
||||||
'public/js/controllers/menuCtrl.js',
|
'public/js/controllers/menuCtrl.js',
|
||||||
'public/js/controllers/notificationCtrl.js',
|
'public/js/controllers/notificationCtrl.js',
|
||||||
'public/js/controllers/rootCtrl.js',
|
'public/js/controllers/rootCtrl.js',
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha test/api.mocha.coffee",
|
"test": "mocha test/api.mocha.coffee",
|
||||||
|
"start": "grunt run:dev",
|
||||||
"postinstall": "./node_modules/bower/bin/bower install -f"
|
"postinstall": "./node_modules/bower/bin/bower install -f"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
window.habitrpg = angular.module('habitrpg',
|
window.habitrpg = angular.module('habitrpg',
|
||||||
['ngRoute', 'ngResource', 'ngSanitize', 'userServices', 'groupServices', 'sharedServices', 'authServices', 'notificationServices', 'ui.bootstrap', 'ui.keypress'])
|
['ngRoute', 'ngResource', 'ngSanitize', 'userServices', 'groupServices', 'memberServices', 'sharedServices', 'authServices', 'notificationServices', 'ui.bootstrap', 'ui.keypress'])
|
||||||
|
|
||||||
.constant("API_URL", "")
|
.constant("API_URL", "")
|
||||||
.constant("STORAGE_USER_ID", 'habitrpg-user')
|
.constant("STORAGE_USER_ID", 'habitrpg-user')
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The character controller:
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
habitrpg.controller('CharacterCtrl',
|
|
||||||
['$scope', '$location', 'User',
|
|
||||||
function($scope, $location, User) {
|
|
||||||
|
|
||||||
$scope.user = User.user;
|
|
||||||
|
|
||||||
$scope.equipped = function(user, type) {
|
|
||||||
var tier = (user.backer && user.backer.tier)
|
|
||||||
return window.habitrpgShared.helpers.equipped(type, user.items[type], user.preferences, tier);
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.$watch('user.tasks', function(){
|
|
||||||
$scope.hpPercent = function(hp) {
|
|
||||||
return (hp / 50) * 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.expPercent = function(exp, level) {
|
|
||||||
return (exp / window.habitrpgShared.algos.tnl(level)) * 100;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
$scope.floor = Math.floor;
|
|
||||||
$scope.count = function(arr) {
|
|
||||||
return _.size(arr);
|
|
||||||
}
|
|
||||||
$scope.tnl = window.habitrpgShared.algos.tnl;
|
|
||||||
|
|
||||||
$scope.showUserAvatar = function() {
|
|
||||||
$('.userAvatar').show()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
@@ -1,17 +1,38 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'API_URL', '$q', 'User',
|
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'API_URL', '$q', 'User', 'Members', '$location',
|
||||||
function($scope, $rootScope, Groups, $http, API_URL, $q, User) {
|
function($scope, $rootScope, Groups, $http, API_URL, $q, User, Members, $location) {
|
||||||
|
|
||||||
$scope.isMember = function(user, group){
|
$scope.isMember = function(user, group){
|
||||||
return ~(group.members.indexOf(user._id));
|
return ~(group.members.indexOf(user._id));
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.groups = Groups.groups;
|
// ------ Loading ------
|
||||||
|
|
||||||
|
$scope.groups = Groups.groups;
|
||||||
$scope.fetchGuilds = Groups.fetchGuilds;
|
$scope.fetchGuilds = Groups.fetchGuilds;
|
||||||
$scope.fetchTavern = Groups.fetchTavern;
|
$scope.fetchTavern = Groups.fetchTavern;
|
||||||
|
|
||||||
|
// ------ Modals ------
|
||||||
|
|
||||||
|
$scope.clickMember = function(uid) {
|
||||||
|
if (User.user._id == uid) {
|
||||||
|
if ($location.path() == '/tasks') {
|
||||||
|
$location.path('/options');
|
||||||
|
} else {
|
||||||
|
$location.path('/tasks');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We need the member information up top here, but then we pass it down to the modal controller
|
||||||
|
// down below. Better way of handling this?
|
||||||
|
debugger
|
||||||
|
Members.selectMember(uid);
|
||||||
|
$rootScope.modals.member = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------ Invites ------
|
||||||
|
|
||||||
$scope.invitee = '';
|
$scope.invitee = '';
|
||||||
$scope.invite = function(group, uuid){
|
$scope.invite = function(group, uuid){
|
||||||
group.$invite({uuid:uuid}, function(){
|
group.$invite({uuid:uuid}, function(){
|
||||||
@@ -22,6 +43,15 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'A
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
.controller("MemberModalCtrl", ['$scope', '$rootScope', 'Members',
|
||||||
|
function($scope, $rootScope, Members) {
|
||||||
|
// We watch Members.selectedMember because it's asynchronously set, so would be a hassle to handle updates here
|
||||||
|
$scope.$watch( function() { return Members.selectedMember; }, function (member) {
|
||||||
|
$scope.profile = member;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
.controller('ChatCtrl', ['$scope', 'Groups', 'User', function($scope, Groups, User){
|
.controller('ChatCtrl', ['$scope', 'Groups', 'User', function($scope, Groups, User){
|
||||||
$scope._chatMessage = '';
|
$scope._chatMessage = '';
|
||||||
$scope.postChat = function(group, message){
|
$scope.postChat = function(group, message){
|
||||||
|
|||||||
@@ -6,17 +6,4 @@ habitrpg.controller("UserAvatarCtrl", ['$scope', '$location', 'User',
|
|||||||
$scope.hideUserAvatar = function() {
|
$scope.hideUserAvatar = function() {
|
||||||
$(".userAvatar").hide();
|
$(".userAvatar").hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.clickAvatar = function(profile) {
|
|
||||||
if (User.user.id == profile.id) {
|
|
||||||
if ($location.path() == '/tasks') {
|
|
||||||
$location.path('/options');
|
|
||||||
} else {
|
|
||||||
$location.path('/tasks');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//TODO show party member modal
|
|
||||||
//$("#avatar-modal-#{uid}").modal('show')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
angular.module('groupServices', ['ngResource']).
|
angular.module('groupServices', ['ngResource']).
|
||||||
factory('Groups', ['API_URL', '$resource', 'User', '$q',
|
factory('Groups', ['API_URL', '$resource', 'User', '$q', 'Members',
|
||||||
function(API_URL, $resource, User, $q) {
|
function(API_URL, $resource, User, $q, Members) {
|
||||||
var Group = $resource(API_URL + '/api/v1/groups/:gid',
|
var Group = $resource(API_URL + '/api/v1/groups/:gid',
|
||||||
{gid:'@_id'},
|
{gid:'@_id'},
|
||||||
{
|
{
|
||||||
@@ -34,6 +34,7 @@ angular.module('groupServices', ['ngResource']).
|
|||||||
// But we don't defer triggering Party, since we always need it for the header if nothing else
|
// But we don't defer triggering Party, since we always need it for the header if nothing else
|
||||||
Group.query({type:'party'}, function(_groups){
|
Group.query({type:'party'}, function(_groups){
|
||||||
partyQ.resolve(_groups[0]);
|
partyQ.resolve(_groups[0]);
|
||||||
|
Members.populate(_groups[0]);
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -42,10 +43,12 @@ angular.module('groupServices', ['ngResource']).
|
|||||||
$('#loading-indicator').show();
|
$('#loading-indicator').show();
|
||||||
Group.query({type:'guilds'}, function(_groups){
|
Group.query({type:'guilds'}, function(_groups){
|
||||||
guildsQ.resolve(_groups);
|
guildsQ.resolve(_groups);
|
||||||
|
Members.populate(_groups);
|
||||||
$('#loading-indicator').hide();
|
$('#loading-indicator').hide();
|
||||||
})
|
})
|
||||||
Group.query({type:'public'}, function(_groups){
|
Group.query({type:'public'}, function(_groups){
|
||||||
publicQ.resolve(_groups);
|
publicQ.resolve(_groups);
|
||||||
|
Members.populate(_groups);
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@@ -54,6 +57,7 @@ angular.module('groupServices', ['ngResource']).
|
|||||||
Group.query({type:'tavern'}, function(_groups){
|
Group.query({type:'tavern'}, function(_groups){
|
||||||
$('#loading-indicator').hide();
|
$('#loading-indicator').hide();
|
||||||
tavernQ.resolve(_groups[0]);
|
tavernQ.resolve(_groups[0]);
|
||||||
|
Members.populate(_groups[0]);
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
73
public/js/services/memberServices.js
Normal file
73
public/js/services/memberServices.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Services that persists and retrieves user from localStorage.
|
||||||
|
*/
|
||||||
|
|
||||||
|
angular.module('memberServices', ['ngResource']).
|
||||||
|
factory('Members', ['API_URL', '$resource',
|
||||||
|
function(API_URL, $resource) {
|
||||||
|
var members = {};
|
||||||
|
var Member = $resource(API_URL + '/api/v1/members/:uid', {uid:'@_id'});
|
||||||
|
return {
|
||||||
|
|
||||||
|
members: members,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows us to lazy-load party / group / public members throughout the application.
|
||||||
|
* @param obj - either a group or an individual member. If it's a group, we lazy-load all of its members.
|
||||||
|
*/
|
||||||
|
populate: function(obj){
|
||||||
|
|
||||||
|
function populateGroup(group){
|
||||||
|
_.each(group.members, function(member){
|
||||||
|
// meaning `populate('members')` wasn't run on the server, so we're getting the "in-database" form of
|
||||||
|
// the members array, which is just a list of IDs - not the populated objects
|
||||||
|
if (_.isString(member)) return;
|
||||||
|
|
||||||
|
// lazy-load
|
||||||
|
if (!members[member._id]) members[member._id] = member;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array of groups
|
||||||
|
if (_.isArray(obj)) {
|
||||||
|
if (obj[0] && obj[0].members) {
|
||||||
|
_.each(obj, function(group){
|
||||||
|
populateGroup(group);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual Group
|
||||||
|
} else if (obj.members)
|
||||||
|
populateGroup(obj);
|
||||||
|
|
||||||
|
// individual Member
|
||||||
|
if (obj._id) {
|
||||||
|
if (!members[obj._id]) {
|
||||||
|
members[obj._id] = obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
selectedMember: undefined,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Once users are populated, we fetch them throughout the application (eg, modals). This
|
||||||
|
* either gets them or fetches if not available
|
||||||
|
* @param uid
|
||||||
|
*/
|
||||||
|
selectMember: function(uid) {
|
||||||
|
var self = this;
|
||||||
|
if (members[uid]) {
|
||||||
|
self.selectedMember = members[uid];
|
||||||
|
} else {
|
||||||
|
Member.get({uid: uid}, function(member){
|
||||||
|
self.populate(member); // lazy load for later
|
||||||
|
self.selectedMember = members[member._id];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
@@ -19,6 +19,14 @@ var api = module.exports;
|
|||||||
var usernameFields = 'auth.local.username auth.facebook.displayName auth.facebook.givenName auth.facebook.familyName auth.facebook.name';
|
var usernameFields = 'auth.local.username auth.facebook.displayName auth.facebook.givenName auth.facebook.familyName auth.facebook.name';
|
||||||
var partyFields = 'profile preferences items stats achievements party backer flags.rest ' + usernameFields;
|
var partyFields = 'profile preferences items stats achievements party backer flags.rest ' + usernameFields;
|
||||||
|
|
||||||
|
api.getMember = function(req, res) {
|
||||||
|
User.findById(req.params.uid).select(partyFields).exec(function(err, user){
|
||||||
|
if (err) return res.json(500,{err:err});
|
||||||
|
if (!user) return res.json(400,{err:'User not found'});
|
||||||
|
res.json(user);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get groups. If req.query.type privided, returned as an array (so ngResource can use). If not, returned as
|
* Get groups. If req.query.type privided, returned as an array (so ngResource can use). If not, returned as
|
||||||
* object {guilds, public, party, tavern}. req.query.type can be comma-separated `type=guilds,party`
|
* object {guilds, public, party, tavern}. req.query.type can be comma-separated `type=guilds,party`
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ router.post('/groups/:gid/chat', auth.auth, groups.attachGroup, groups.postChat)
|
|||||||
//PUT /groups/:gid/chat/:messageId
|
//PUT /groups/:gid/chat/:messageId
|
||||||
//DELETE /groups/:gid/chat/:messageId
|
//DELETE /groups/:gid/chat/:messageId
|
||||||
|
|
||||||
|
/* Members */
|
||||||
|
router.get('/members/:uid', groups.getMember);
|
||||||
|
|
||||||
// Market
|
// Market
|
||||||
router.post('/market/buy', auth.auth, user.marketBuy);
|
router.post('/market/buy', auth.auth, user.marketBuy);
|
||||||
|
|
||||||
|
|||||||
@@ -52,13 +52,13 @@ html
|
|||||||
script(type='text/javascript', src='/js/services/sharedServices.js')
|
script(type='text/javascript', src='/js/services/sharedServices.js')
|
||||||
script(type='text/javascript', src='/js/services/userServices.js')
|
script(type='text/javascript', src='/js/services/userServices.js')
|
||||||
script(type='text/javascript', src='/js/services/groupServices.js')
|
script(type='text/javascript', src='/js/services/groupServices.js')
|
||||||
|
script(type='text/javascript', src='/js/services/memberServices.js')
|
||||||
|
|
||||||
script(type='text/javascript', src='/js/filters/filters.js')
|
script(type='text/javascript', src='/js/filters/filters.js')
|
||||||
|
|
||||||
script(type='text/javascript', src='/js/directives/directives.js')
|
script(type='text/javascript', src='/js/directives/directives.js')
|
||||||
|
|
||||||
script(type='text/javascript', src='/js/controllers/authCtrl.js')
|
script(type='text/javascript', src='/js/controllers/authCtrl.js')
|
||||||
script(type='text/javascript', src='/js/controllers/characterCtrl.js')
|
|
||||||
script(type='text/javascript', src='/js/controllers/menuCtrl.js')
|
script(type='text/javascript', src='/js/controllers/menuCtrl.js')
|
||||||
script(type='text/javascript', src='/js/controllers/notificationCtrl.js')
|
script(type='text/javascript', src='/js/controllers/notificationCtrl.js')
|
||||||
script(type='text/javascript', src='/js/controllers/rootCtrl.js')
|
script(type='text/javascript', src='/js/controllers/rootCtrl.js')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
li(ng-repeat='message in group.chat', ng-class='{highlight: message.text.indexOf(username(user.auth,user.profile.name)) != -1}')
|
li(ng-repeat='message in group.chat', ng-class='{highlight: message.text.indexOf(username(user.auth,user.profile.name)) != -1}')
|
||||||
span.label.chat-message(class='{{nameTagClasses(message)}}', tooltip='{{message.contributor}}')
|
a.label.chat-message(class='{{nameTagClasses(message)}}', tooltip='{{message.contributor}}', ng-click='clickMember(message.uuid)')
|
||||||
| {{message.user}}
|
| {{message.user}}
|
||||||
span
|
span
|
||||||
span(ng-bind-html="message.text | linky:'_blank'") -
|
span(ng-bind-html="message.text | linky:'_blank'") -
|
||||||
|
|||||||
@@ -1,68 +1,66 @@
|
|||||||
div#groups-controller(ng-controller='GroupsCtrl')
|
// FIXME note, due to https://github.com/angular-ui/bootstrap/issues/783 we can't use nested angular-bootstrap tabs
|
||||||
|
// Subscribe to that ticket & change this when they fix
|
||||||
|
|
||||||
// FIXME note, due to https://github.com/angular-ui/bootstrap/issues/783 we can't use nested angular-bootstrap tabs
|
ul.nav.nav-tabs
|
||||||
// Subscribe to that ticket & change this when they fix
|
li.active
|
||||||
|
a(data-target='#groups-party', data-toggle='tab') Party
|
||||||
|
li
|
||||||
|
a(data-target='#groups-guilds', data-toggle='tab', ng-click='fetchGuilds()') Guilds
|
||||||
|
|
||||||
ul.nav.nav-tabs
|
.tab-content(ng-controller='PartyCtrl')
|
||||||
li.active
|
#groups-party.tab-pane.active
|
||||||
a(data-target='#groups-party', data-toggle='tab') Party
|
div(ng-show='group._id')
|
||||||
li
|
include ./group
|
||||||
a(data-target='#groups-guilds', data-toggle='tab', ng-click='fetchGuilds()') Guilds
|
div(ng-hide='group._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 {{user.invitations.party.name}}
|
||||||
|
a.btn.btn-success(data-type='party', ng-click='join(user.invitations.party)') Accept
|
||||||
|
a.btn.btn-danger(ng-click='reject(group)') 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-content(ng-controller='PartyCtrl')
|
#groups-guilds.tab-pane(ng-controller='GuildsCtrl')
|
||||||
#groups-party.tab-pane.active
|
ul.nav.nav-tabs
|
||||||
div(ng-show='group._id')
|
li.active
|
||||||
|
a(data-target='#groups-public-guilds', data-toggle='tab') Public Guilds
|
||||||
|
li(ng-repeat='group in groups.guilds')
|
||||||
|
a(data-target='#groups-guild-{{group._id}}', data-toggle='tab') {{group.name}}
|
||||||
|
li
|
||||||
|
a(data-target='#groups-create-guild', data-toggle='tab') Create Guild
|
||||||
|
.tab-content
|
||||||
|
.tab-pane.active#groups-public-guilds
|
||||||
|
div(ng-repeat='invitation in user.invitations.guilds')
|
||||||
|
h3 You're Invited To {{invitation.name}}
|
||||||
|
a.btn.btn-success(data-type='guild', ng-click='join(group)') Accept
|
||||||
|
a.btn.btn-danger(x-bind='click:rejectInvitation') Reject
|
||||||
|
// Public Groups
|
||||||
|
.options-group.option-large.whatever-options
|
||||||
|
input.option-content(type='text',ng-model='guildSearch', placeholder='Search')
|
||||||
|
table.table.table-striped
|
||||||
|
tr(ng-repeat='group in groups.public | filter:guildSearch')
|
||||||
|
td
|
||||||
|
ul.pull-right.challenge-accordion-header-specs
|
||||||
|
li {{group.members.length}} member(s)
|
||||||
|
li
|
||||||
|
// join / leave
|
||||||
|
a.btn.btn-small.btn-danger(ng-show='isMember(user, group)', ng-click='leave(group)')
|
||||||
|
i.icon-ban-circle
|
||||||
|
| Leave
|
||||||
|
a.btn.btn-small.btn-success(ng-hide='isMember(user, group)', ng-click='join(group)')
|
||||||
|
i.icon-ok
|
||||||
|
| Join
|
||||||
|
h4 {{group.name}}
|
||||||
|
p {{group.description}}
|
||||||
|
.tab-pane(id='groups-guild-{{group._id}}', ng-repeat='group in groups.guilds')
|
||||||
include ./group
|
include ./group
|
||||||
div(ng-hide='group._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 {{user.invitations.party.name}}
|
|
||||||
a.btn.btn-success(data-type='party', ng-click='join(user.invitations.party)') Accept
|
|
||||||
a.btn.btn-danger(ng-click='reject(group)') 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
|
|
||||||
|
|
||||||
#groups-guilds.tab-pane(ng-controller='GuildsCtrl')
|
.tab-pane#groups-create-guild
|
||||||
ul.nav.nav-tabs
|
include ./create-group
|
||||||
li.active
|
|
||||||
a(data-target='#groups-public-guilds', data-toggle='tab') Public Guilds
|
|
||||||
li(ng-repeat='group in groups.guilds')
|
|
||||||
a(data-target='#groups-guild-{{group._id}}', data-toggle='tab') {{group.name}}
|
|
||||||
li
|
|
||||||
a(data-target='#groups-create-guild', data-toggle='tab') Create Guild
|
|
||||||
.tab-content
|
|
||||||
.tab-pane.active#groups-public-guilds
|
|
||||||
div(ng-repeat='invitation in user.invitations.guilds')
|
|
||||||
h3 You're Invited To {{invitation.name}}
|
|
||||||
a.btn.btn-success(data-type='guild', ng-click='join(group)') Accept
|
|
||||||
a.btn.btn-danger(x-bind='click:rejectInvitation') Reject
|
|
||||||
// Public Groups
|
|
||||||
.options-group.option-large.whatever-options
|
|
||||||
input.option-content(type='text',ng-model='guildSearch', placeholder='Search')
|
|
||||||
table.table.table-striped
|
|
||||||
tr(ng-repeat='group in groups.public | filter:guildSearch')
|
|
||||||
td
|
|
||||||
ul.pull-right.challenge-accordion-header-specs
|
|
||||||
li {{group.members.length}} member(s)
|
|
||||||
li
|
|
||||||
// join / leave
|
|
||||||
a.btn.btn-small.btn-danger(ng-show='isMember(user, group)', ng-click='leave(group)')
|
|
||||||
i.icon-ban-circle
|
|
||||||
| Leave
|
|
||||||
a.btn.btn-small.btn-success(ng-hide='isMember(user, group)', ng-click='join(group)')
|
|
||||||
i.icon-ok
|
|
||||||
| Join
|
|
||||||
h4 {{group.name}}
|
|
||||||
p {{group.description}}
|
|
||||||
.tab-pane(id='groups-guild-{{group._id}}', ng-repeat='group in groups.guilds')
|
|
||||||
include ./group
|
|
||||||
|
|
||||||
.tab-pane#groups-create-guild
|
|
||||||
include ./create-group
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
figure.herobox(ng-click='clickAvatar(profile)', data-name='{{username(profile.auth, profile.profile.name)}}', ng-class='{isUser: profile.id==user.id, hasPet: profile.items.pet}', data-level='{{profile.stats.lvl}}', data-uid='{{profile.id}}', rel='popover', data-placement='bottom', data-trigger='hover', data-html='true', data-content="<div ng-hide='profile.id == user.id'> <div class='progress progress-danger' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.hp, 50)}}%;'></div> </div> <div class='progress progress-warning' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.exp, tnl(profile.stats.lvl))}}%;'></div> </div> <div>Level: {{profile.stats.lvl}}</div> <div>GP: {{profile.stats.gp | number:0}}</div> <div>{{count(profile.items.pets)}} / 90 Pets Found</div> </div>")
|
figure.herobox(ng-click='clickMember(profile._id)', data-name='{{username(profile.auth, profile.profile.name)}}', ng-class='{isUser: profile.id==user.id, hasPet: profile.items.pet}', data-level='{{profile.stats.lvl}}', data-uid='{{profile.id}}', rel='popover', data-placement='bottom', data-trigger='hover', data-html='true', data-content="<div ng-hide='profile.id == user.id'> <div class='progress progress-danger' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.hp, 50)}}%;'></div> </div> <div class='progress progress-warning' style='height:5px;'> <div class='bar' style='height: 5px; width: {{percent(profile.stats.exp, tnl(profile.stats.lvl))}}%;'></div> </div> <div>Level: {{profile.stats.lvl}}</div> <div>GP: {{profile.stats.gp | number:0}}</div> <div>{{count(profile.items.pets)}} / 90 Pets Found</div> </div>")
|
||||||
.character-sprites
|
.character-sprites
|
||||||
span(ng-class='{zzz:profile.flags.rest}')
|
span(ng-class='{zzz:profile.flags.rest}')
|
||||||
span(class='{{profile.preferences.gender}}_skin_{{profile.preferences.skin}}')
|
span(class='{{profile.preferences.gender}}_skin_{{profile.preferences.skin}}')
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ include ./reroll
|
|||||||
include ./death
|
include ./death
|
||||||
include ./new-stuff
|
include ./new-stuff
|
||||||
include ./why-ads
|
include ./why-ads
|
||||||
include ./more-gems
|
include ./more-gems
|
||||||
|
include ./members
|
||||||
@@ -1,40 +1,27 @@
|
|||||||
{{#each _membersArray as :member}}
|
<div ng-controller="MemberModalCtrl">
|
||||||
<app:modals:modal modalId="avatar-modal-{{:member.id}}">
|
<div modal="modals.member">
|
||||||
<app:avatar:profile profile={{_members[:member.id]}} />
|
<app:avatar:profile />
|
||||||
|
|
||||||
<!-- see above -->
|
<!-- see above -->
|
||||||
<profile:>
|
<h2 class='profile-modal-header'>{{username(profile.auth, profile.profile.name)}}</h2>
|
||||||
<h2 class='profile-modal-header'>{{username(@profile.auth, @profile.profile.name)}}</h2>
|
|
||||||
<hr/>
|
<hr/>
|
||||||
<div class='row-fluid'>
|
<div class='row-fluid'>
|
||||||
<div class='span6'>
|
<div class='span6'>
|
||||||
{{#if @profile.profile.imageUrl}}
|
<img ng-show='profile.profile.imageUrl' ng-src="{{profile.profile.imageUrl}}" />
|
||||||
<img src="{{@profile.profile.imageUrl}}" />
|
<p ng-show="profile.profile.blurb">{{profile.profile.blurb}}</p>
|
||||||
{{/}}
|
<ul ng-show="profile.profile.websites">
|
||||||
{{#if @profile.profile.blurb}}
|
<li ng-repeat="website in profile.profile.websites">{{website}}</li>
|
||||||
<p>{{@profile.profile.blurb}}</p>
|
|
||||||
{{/}}
|
|
||||||
{{#if @profile.profile.websites}}
|
|
||||||
<ul>
|
|
||||||
{{#each @profile.profile.websites as :website}}
|
|
||||||
<li>{{:website}}</li>
|
|
||||||
{{/}}
|
|
||||||
</ul>
|
</ul>
|
||||||
{{/}}
|
|
||||||
<h3>Stats</h3>
|
<h3>Stats</h3>
|
||||||
<app:avatar:profile-stats profile={{@profile}} />
|
<app:avatar:profile-stats profile={{profile}} />
|
||||||
</div>
|
</div>
|
||||||
<div class='span6'>
|
<div class='span6'>
|
||||||
<h3>Achievements</h3>
|
<h3>Achievements</h3>
|
||||||
<app:avatar:achievements profile={{@profile}} />
|
<app:avatar:achievements profile={{profile}} />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<footer>
|
||||||
|
<button data-dismiss="modal" class="btn btn-success">Ok</button>
|
||||||
|
</footer>
|
||||||
<@footer>
|
</div>
|
||||||
<button data-dismiss="modal" class="btn btn-success">Ok</button>
|
</div>
|
||||||
</@footer>
|
|
||||||
</app:modals:modal>
|
|
||||||
{{/}}
|
|
||||||
|
|||||||
21
views/shared/modals/members.jade
Normal file
21
views/shared/modals/members.jade
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
div(ng-controller='MemberModalCtrl')
|
||||||
|
div(modal='modals.member')
|
||||||
|
//-.modal-header
|
||||||
|
h3 username
|
||||||
|
.modal-body
|
||||||
|
h2.profile-modal-header {{username(profile.auth, profile.profile.name)}}
|
||||||
|
app:avatar:profile
|
||||||
|
hr
|
||||||
|
.row-fluid
|
||||||
|
.span6
|
||||||
|
img(ng-show='profile.profile.imageUrl', ng-src='{{profile.profile.imageUrl}}')
|
||||||
|
p(ng-show='profile.profile.blurb') {{profile.profile.blurb}}
|
||||||
|
ul(ng-show='profile.profile.websites')
|
||||||
|
li(ng-repeat='website in profile.profile.websites') {{website}}
|
||||||
|
h3 Stats
|
||||||
|
app:avatar:profile-stats
|
||||||
|
.span6
|
||||||
|
h3 Achievements
|
||||||
|
app:avatar:achievements
|
||||||
|
.modal-footer
|
||||||
|
button.btn.btn-default(ng-click='modals.member = false') Ok
|
||||||
Reference in New Issue
Block a user