challenges: switch from ngRoute to ui-router

This commit is contained in:
Tyler Renelle
2013-10-27 22:27:07 -07:00
parent f178eb2322
commit 35c4a62de0
23 changed files with 614 additions and 708 deletions

View File

@@ -19,7 +19,7 @@
"angular-resource": "1.2.0-rc.2",
"angular-ui": "~0.4.0",
"angular-bootstrap": "~0.5.0",
"habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#rewrite",
"habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git#challenges",
"bootstrap-tour": "0.5.0",
"BrowserQuest": "https://github.com/mozilla/BrowserQuest.git",
"github-buttons": "git://github.com/mdo/github-buttons.git",
@@ -29,11 +29,11 @@
"sticky": "*",
"bootstrap-datepicker": "~1.2.0",
"bootstrap": "v2.3.2",
"angular-route": "1.2.0-rc.2",
"angular-ui-utils": "~0.0.4",
"angular-sanitize": "1.2.0-rc.2",
"marked": "~0.2.9",
"JavaScriptButtons": "git://github.com/paypal/JavaScriptButtons.git#master"
"JavaScriptButtons": "git://github.com/paypal/JavaScriptButtons.git#master",
"angular-ui-router": "eda67d2da08cbe2aa1aa39ef154a87c7afe480ec"
},
"resolutions": {
"jquery": "~2.0.3",

View File

@@ -1,21 +1,123 @@
"use strict";
window.habitrpg = angular.module('habitrpg',
['ngRoute', 'ngResource', 'ngSanitize', 'userServices', 'groupServices', 'memberServices', 'challengeServices', 'sharedServices', 'authServices', 'notificationServices', 'guideServices', 'ui.bootstrap', 'ui.keypress'])
['ngRoute', 'ngResource', 'ngSanitize', 'userServices', 'groupServices', 'memberServices', 'challengeServices', 'sharedServices', 'authServices', 'notificationServices', 'guideServices', 'ui.bootstrap', 'ui.keypress', 'ui.router'])
.constant("API_URL", "")
.constant("STORAGE_USER_ID", 'habitrpg-user')
.constant("STORAGE_SETTINGS_ID", 'habit-mobile-settings')
//.constant("STORAGE_GROUPS_ID", "") // if we decide to take groups offline
.config(['$routeProvider', '$httpProvider', 'STORAGE_SETTINGS_ID',
function($routeProvider, $httpProvider, STORAGE_SETTINGS_ID) {
$routeProvider
//.when('/login', {templateUrl: 'views/login.html'})
.when('/tasks', {templateUrl: 'templates/habitrpg-main.html'})
.when('/options', {templateUrl: 'templates/habitrpg-options.html'})
.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'STORAGE_SETTINGS_ID',
function($stateProvider, $urlRouterProvider, $httpProvider, STORAGE_SETTINGS_ID) {
.otherwise({redirectTo: '/tasks'});
$urlRouterProvider
// Setup default selected tabs
.when('/options', '/options/profile/avatar')
.when('/options/profile', '/options/profile/avatar')
.when('/options/groups', '/options/groups/tavern')
.when('/options/inventory', '/options/inventory/inventory')
// redirect states that don't match
.otherwise("/tasks");
$stateProvider
// Tasks
.state('tasks', {
url: "/tasks",
templateUrl: "partials/main.html"
})
// Options
.state('options', {
url: "/options",
templateUrl: "partials/options.html",
controller: function(){}
})
// Options > Profile
.state('options.profile', {
url: "/profile",
templateUrl: "partials/options.profile.html",
controller: 'UserCtrl'
})
.state('options.profile.avatar', {
url: "/avatar",
templateUrl: "partials/options.profile.avatar.html"
})
.state('options.profile.stats', {
url: "/stats",
templateUrl: "partials/options.profile.stats.html"
})
.state('options.profile.profile', {
url: "/stats",
templateUrl: "partials/options.profile.profile.html"
})
// Options > Groups
.state('options.groups', {
url: "/groups",
templateUrl: "partials/options.groups.html"
})
.state('options.groups.tavern', {
url: "/tavern",
templateUrl: "partials/options.groups.tavern.html",
controller: 'TavernCtrl'
// TODO this doesn't work, seems ngResource doesn't get the .then() function
// resolve: {
// group: ['Groups', function(Groups){
// //return Groups.fetchTavern();
// }]
// }
})
.state('options.groups.party', {
url: '/party',
templateUrl: "partials/options.groups.party.html",
controller: 'PartyCtrl'
})
.state('options.groups.guilds', {
url: '/party',
templateUrl: "partials/options.groups.guilds.html",
controller: 'GuildsCtrl'
})
// Options > Inventory
.state('options.inventory', {
url: '/inventory',
templateUrl: "partials/options.inventory.html"
})
.state('options.inventory.inventory', {
url: '/inventory',
templateUrl: "partials/options.inventory.inventory.html"
})
.state('options.inventory.stable', {
url: '/stable',
templateUrl: "partials/options.inventory.stable.html"
})
// Options > Challenges
.state('options.challenges', {
url: "/challenges",
controller: 'ChallengesCtrl',
templateUrl: "partials/options.challenges.html",
resolve: {
groups: ['$http', 'API_URL', function($http, API_URL){
// TODO come up with more unified ngResource-style approach
return $http.get(API_URL + '/api/v1/groups?minimal=true');
}],
challenges: ['Challenges', function(Challenges){
return Challenges.Challenge.query();
}]
}
})
// Options > Settings
.state('options.settings', {
url: "/settings",
controller: 'SettingsCtrl',
templateUrl: "partials/options.settings.html"
})
var settings = JSON.parse(localStorage.getItem(STORAGE_SETTINGS_ID));
if (settings && settings.auth) {

View File

@@ -1,13 +1,11 @@
"use strict";
habitrpg.controller("ChallengesCtrl", ['$scope', '$rootScope', 'User', 'Challenges', 'Notification', '$http', 'API_URL', '$compile',
function($scope, $rootScope, User, Challenges, Notification, $http, API_URL, $compile) {
habitrpg.controller("ChallengesCtrl", ['$scope', 'User', 'Challenges', 'Notification', '$compile', 'groups', 'challenges',
function($scope, User, Challenges, Notification, $compile, groups, challenges) {
$http.get(API_URL + '/api/v1/groups?minimal=true').success(function(groups){
$scope.groups = groups;
});
$scope.challenges = Challenges.Challenge.query();
// groups & challenges are loaded as `resolve` via ui-router (see app.js)
$scope.groups = groups;
$scope.challenges = challenges;
//------------------------------------------------------------
// Challenge
@@ -92,61 +90,33 @@ habitrpg.controller("ChallengesCtrl", ['$scope', '$rootScope', 'User', 'Challeng
// TODO persist
}
/**
* Render graphs for user scores when the "Challenges" tab is clicked
*/
//TODO
// 1. on main tab click or party
// * sort & render graphs for party
// 2. guild -> all guilds
// 3. public -> all public
// $('#profile-challenges-tab-link').on 'shown', ->
// async.each _.toArray(model.get('groups')), (g) ->
// async.each _.toArray(g.challenges), (chal) ->
// async.each _.toArray(chal.tasks), (task) ->
// async.each _.toArray(chal.members), (member) ->
// if (history = member?["#{task.type}s"]?[task.id]?.history) and !!history
// data = google.visualization.arrayToDataTable _.map(history, (h)-> [h.date,h.value])
// options =
// backgroundColor: { fill:'transparent' }
// width: 150
// height: 50
// chartArea: width: '80%', height: '80%'
// axisTitlePosition: 'none'
// legend: position: 'bottom'
// hAxis: gridlines: color: 'transparent' # since you can't seem to *remove* gridlines...
// vAxis: gridlines: color: 'transparent'
// chart = new google.visualization.LineChart $(".challenge-#{chal.id}-member-#{member.id}-history-#{task.id}")[0]
// chart.draw(data, options)
/*
--------------------------
Unsubscribe functions
--------------------------
*/
/*
--------------------------
Unsubscribe functions
--------------------------
*/
$scope.unsubscribe = function(keep) {
if (keep == 'cancel') {
$scope.selectedChal = undefined;
} else {
$scope.selectedChal.$leave({keep:keep});
}
$scope.popoverEl.popover('destroy');
}
$scope.clickUnsubscribe = function(chal, $event) {
$scope.selectedChal = chal;
$scope.popoverEl = $($event.target);
var html = $compile(
'<a ng-controller="ChallengesCtrl" ng-click="unsubscribe(\'remove-all\')">Remove Tasks</a><br/>\n<a ng-click="unsubscribe(\'keep-all\')">Keep Tasks</a><br/>\n<a ng-click="unsubscribe(\'cancel\')">Cancel</a><br/>'
)($scope);
$scope.popoverEl.popover('destroy').popover({
html: true,
placement: 'top',
trigger: 'manual',
title: 'Unsubscribe From Challenge And:',
content: html
}).popover('show');
$scope.unsubscribe = function(keep) {
if (keep == 'cancel') {
$scope.selectedChal = undefined;
} else {
$scope.selectedChal.$leave({keep:keep});
}
$scope.popoverEl.popover('destroy');
}
$scope.clickUnsubscribe = function(chal, $event) {
$scope.selectedChal = chal;
$scope.popoverEl = $($event.target);
var html = $compile(
'<a ng-controller="ChallengesCtrl" ng-click="unsubscribe(\'remove-all\')">Remove Tasks</a><br/>\n<a ng-click="unsubscribe(\'keep-all\')">Keep Tasks</a><br/>\n<a ng-click="unsubscribe(\'cancel\')">Cancel</a><br/>'
)($scope);
$scope.popoverEl.popover('destroy').popover({
html: true,
placement: 'top',
trigger: 'manual',
title: 'Unsubscribe From Challenge And:',
content: html
}).popover('show');
}
}]);

View File

@@ -1,7 +1,7 @@
"use strict";
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'API_URL', '$q', 'User', 'Members', '$location',
function($scope, $rootScope, Groups, $http, API_URL, $q, User, Members, $location) {
habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'API_URL', '$q', 'User', 'Members', '$location', '$state',
function($scope, $rootScope, Groups, $http, API_URL, $q, User, Members, $location, $state) {
$scope.isMember = function(user, group){
return ~(group.members.indexOf(user._id));
@@ -25,10 +25,10 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'A
$scope.clickMember = function(uid, forceShow) {
if (User.user._id == uid && !forceShow) {
if ($location.path() == '/tasks') {
$location.path('/options');
if ($state.is('tasks')) {
$state.go('options');
} else {
$location.path('/tasks');
$state.go('tasks');
}
} else {
// We need the member information up top here, but then we pass it down to the modal controller
@@ -117,6 +117,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'A
.controller("GuildsCtrl", ['$scope', 'Groups', 'User', '$rootScope',
function($scope, Groups, User, $rootScope) {
Groups.fetchGuilds();
$scope.type = 'guild';
$scope.text = 'Guild';
$scope.newGroup = new Groups.Group({type:'guild', privacy:'private', leader: User.user._id, members: [User.user._id]});
@@ -202,6 +203,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'A
.controller("TavernCtrl", ['$scope', 'Groups', 'User',
function($scope, Groups, User) {
Groups.fetchTavern();
$scope.group = Groups.groups.tavern;
$scope.rest = function(){

View File

@@ -3,8 +3,8 @@
/* Make user and settings available for everyone through root scope.
*/
habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http',
function($scope, $rootScope, $location, User, $http) {
habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$http', '$state', '$stateParams',
function($scope, $rootScope, $location, User, $http, $state, $stateParams) {
$rootScope.modals = {};
$rootScope.modals.achievements = {};
$rootScope.User = User;
@@ -12,6 +12,10 @@ habitrpg.controller("RootCtrl", ['$scope', '$rootScope', '$location', 'User', '$
$rootScope.settings = User.settings;
$rootScope.flash = {errors: [], warnings: []};
// Angular UI Router
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
// indexOf helper
$scope.indexOf = function(haystack, needle){
return ~haystack.indexOf(needle);

View File

@@ -44,9 +44,9 @@ angular.module('groupServices', ['ngResource']).
fetchGuilds: _.once(function(){
$('#loading-indicator').show();
Group.query({type:'guilds'}, function(_groups){
$('#loading-indicator').hide();
guildsQ.resolve(_groups);
Members.populate(_groups);
$('#loading-indicator').hide();
})
Group.query({type:'public'}, function(_groups){
publicQ.resolve(_groups);
@@ -58,8 +58,8 @@ angular.module('groupServices', ['ngResource']).
$('#loading-indicator').show();
Group.query({type:'tavern'}, function(_groups){
$('#loading-indicator').hide();
tavernQ.resolve(_groups[0]);
Members.populate(_groups[0]);
tavernQ.resolve(_groups[0]);
})
}),

View File

@@ -20,6 +20,8 @@ var ChallengeSchema = new Schema({
//},
timestamp: {type: Date, 'default': Date.now},
members: [{type: String, ref: 'User'}]
}, {
minimize: 'false'
});
ChallengeSchema.virtual('tasks').get(function () {

View File

@@ -7,37 +7,14 @@ var GroupSchema = new Schema({
_id: {type: String, 'default': helpers.uuid},
name: String,
description: String,
leader: {
type: String,
ref: 'User'
},
members: [
{
type: String,
ref: 'User'
}
],
invites: [
{
type: String,
ref: 'User'
}
],
type: {
type: String,
"enum": ['guild', 'party']
},
privacy: {
type: String,
"enum": ['private', 'public']
},
_v: {
Number: Number,
'default': 0
},
leader: {type: String, ref: 'User'},
members: [{type: String, ref: 'User'}],
invites: [{type: String, ref: 'User'}],
type: {type: String, "enum": ['guild', 'party']},
privacy: {type: String, "enum": ['private', 'public']},
_v: {Number: Number,'default': 0},
websites: Array,
chat: Array,
/*
# [{
# timestamp: Date

View File

@@ -31,6 +31,8 @@ var TaskSchema = new Schema({
broken: String // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, etc
// group: {type: 'Strign', ref: 'Group'} // if we restore this, rename `id` above to `challenge`
}
}, {
minimize: 'false'
});
TaskSchema.methods.toJSON = function() {

View File

@@ -31,6 +31,7 @@ html
script(type='text/javascript', src='/bower_components/bootstrap-growl/jquery.bootstrap-growl.min.js')
script(type='text/javascript', src='/bower_components/bootstrap-tour/build/js/bootstrap-tour.min.js')
script(type='text/javascript', src='/bower_components/angular/angular.js')
script(type='text/javascript', src='/bower_components/angular-ui-router/release/angular-ui-router.js')
script(type='text/javascript', src='/bower_components/angular-sanitize/angular-sanitize.min.js')
script(type='text/javascript', src='/bower_components/marked/lib/marked.js')
@@ -109,7 +110,7 @@ html
.exp-chart(ng-show='charts.exp')
#main(ng-view)
#main(ui-view)
include ./shared/footer

View File

@@ -1,4 +1,4 @@
script(id='templates/habitrpg-main.html', type="text/ng-template")
script(id='partials/main.html', type="text/ng-template")
include ./filters
div(ng-controller='TasksCtrl')
habitrpg-tasks(main='true', obj='user')

View File

@@ -1,176 +0,0 @@
<main>
<app:widgets:tabs>
<!--<@headers>-->
<app:widgets:tab-header group="challenges" tab="party" title="Party" default="true" />
<app:widgets:tab-header group="challenges" tab="guild" title="Guild" />
<app:widgets:tab-header group="challenges" tab="public" title="Public" />
<!--</@headers>-->
<app:widgets:tab-content group="challenges" tab="party" default="true">
{{#unless _page.party.id}}
Join a party first.
{{else}}
<app:challenges:list type="party" gid="{{_page.party.id}}" text="Party" list="{_page.lists.challenges[_page.party.id]}" />
{{/}}
</app:widgets:tab-content>
<app:widgets:tab-content group="challenges" tab="guild">
<ul class="nav nav-pills">
{{#each _page.guilds as :guild}}
<li class="{{#if equal($index,0)}}active{{/}}"><a data-toggle='tab' data-target="#challenges-guild-{:guild.id}">{{:guild.name}}</a></li>
{{/}}
</ul>
<div class="tab-content">
{{#each _page.guilds as :guild}}
<div class="tab-pane {{#if equal($index,0)}}active{{/}}" id="challenges-guild-{{:guild.id}}">
<app:challenges:list type="guild" gid="{{:guild.id}}" text="Guild" list="{_page.lists.challenges[:guild.id]}" />
</div>
{{/}}
</div>
</app:widgets:tab-content>
<app:widgets:tab-content group="challenges" tab="public">
<app:challenges:list type="public" gid="habitrpg" text="Public" list="{_page.lists.challenges.habitrpg}" />
</app:widgets:tab-content>
</app:widgets:tabs>
</main>
<list>
<div class="{#unless _page.new.challenge}hidden{/}">
<app:challenges:create-form />
</div>
<div class="{#if _page.new.challenge}hidden{/}">
<app:challenges:create-button type='{{@type}}' gid={{@gid}} text={{@text}} />
{#each @list as :challenge}
<app:challenges:list-entry challenge={:challenge} />
{/}
<hr/>
</div>
</list>
<list-entry>
<div class="accordion-group">
<div class="accordion-heading">
<ul class='pull-right challenge-accordion-header-specs'>
<li>
{count(@challenge.members)} Subscribers
</li>
<li>
<!-- prize -->
{#if @challenge.prize}
<table><tr><td>{@challenge.prize}</td><td><span class="Pet_Currency_Gem1x"></span></td><td> Prize</td></tr></table>
{/}
</li>
<li>
<!-- subscribe / unsubscribe -->
{#with @challenge}
<a x-bind="click:challenges.challengeUnsubscribe" class='btn btn-small btn-danger {#unless indexOf(_page.user.pub.challenges,@challenge.id)}hidden{/}'><i class='icon-ban-circle'></i> Unsubscribe</a>
<a x-bind="click:challenges.subscribe" class='btn btn-small btn-success {#if indexOf(_page.user.pub.challenges,@challenge.id)}hidden{/}'><i class='icon-ok'></i> Subscribe</a>
{/}
</li>
</ul>
<a class="accordion-toggle" data-toggle="collapse" href="#accordion-challenge-{{@challenge.id}}">{@challenge.name} (by {@challenge.user.name})</a>
</div>
<div id="accordion-challenge-{{@challenge.id}}" class="accordion-body collapse">
<div class="accordion-inner">
<!-- Edit button -->
<span style='position:absolute; right:0;'>
{#if and(not(_page.editing.challenges[@challenge.id]),equal(@challenge.user.uid,_session.userId))}
<ul class='nav nav-pills'><li>
<a x-bind='click:challenges.toggleEdit' data-id={{@challenge.id}} ><i class=icon-pencil></i></a>
</li></ul>
{else}
<ul class='nav nav-pills'><li>
<a x-bind='click:challenges.toggleEdit' data-id={{@challenge.id}} ><i class=icon-ok></i></a>
</li></ul>
{/}
</span>
{#if _page.editing.challenges[@challenge.id]}
<div class='-options'>
<input type=text class='option-content' value={@challenge.name} />
<textarea cols=3 class='option-content' placeholder='Description'>{@challenge.description}</textarea>
<!--<input type=number class='option-content' placeholder='Gems Prize' value={@challenge.prize} />-->
</div>
{{#with @challenge}}
<a class='btn btn-small btn-danger' x-bind=click:challenges.delete >Delete</a>
{{/}}
{/}
{#if @challenge.description}<div>{@challenge.description}</div>{/}
<div class="grid">
<app:tasks:task-lists
editable={_page.editing.challenges[@challenge.id]}
habits={@challenge.habits}
dailys={@challenge.dailys}
todos={@challenge.todos}
rewards={@challenge.rewards}
/>
</div>
<h3>Statistics</h3>
{#each @challenge.members as :member}
<h4>{:member.name}</h4>
<div class="grid">
<div class="module">
<app:challenges:stats header=Habits challenge={@challenge} member={:member} list={@challenge.habits} />
</div>
<div class="module">
<app:challenges:stats header=Dailies challenge={@challenge} member={:member} list={@challenge.dailys} />
</div>
<div class="module">
<app:challenges:stats header=Todos challenge={@challenge} member={:member} list={@challenge.todos} />
</div>
</div>
{/}
</div>
</div>
</div>
</list-entry>
<stats>
<h5>{@header}</h5>
<div>
{#each @list as :task}
<table><tr>
<td>
<!-- FIXME commented section below isn't getting updated dynamically, temp solution is less efficient -->
<strong>{:task.text}</strong>: {challengeMemberScore(@member,:task)} <!--{round(@member[@taskType]s[:task.id].value)}-->
</td>
<td>
<div style='margin-left: 10px' class="challenge-{{@challenge.id}}-member-{{@member.id}}-history-{{:task.id}}"></div>
</td>
</tr></table>
{/}
</div>
</stats>
<create-button>
<a x-bind='click:challenges.create' class='btn btn-success' data-type={{@type}} data-gid={{@gid}} >Create {{@text}} Challenge</a>
</create-button>
<create-form>
<form x-bind="submit:challenges.save">
<div>
<input type='submit' class='btn btn-success' value='Save' />
<input type='button' x-bind='click:challenges.discard' class='btn btn-danger' value=Discard />
</div>
<div class='challenge-options'>
<input type='text' class='option-content' value={_page.new.challenge.name} placeholder="Challenge Title" required />
</div>
</form>
<div class="grid">
<app:tasks:task-lists
habits={_page.new.challenge.habits}
dailys={_page.new.challenge.dailys}
todos={_page.new.challenge.todos}
rewards={_page.new.challenge.rewards}
editable=true />
</div>
</create-form>

View File

@@ -1,73 +1,74 @@
.row-fluid(ng-controller='ChallengesCtrl')
.span2.well
h4 Filters
ul
li(ng-repeat='group in groups')
input(type='checkbox', ng-model='search.group')
| {{group.name}}
li
input(type='checkbox', ng-model='search.members')
| Subscribed (TODO)
li
input(type='checkbox', ng-model='search.members')
| Available (TODO)
.span10
// Creation form
a.btn.btn-success(ng-click='create()') Create Challenge
.create-challenge-from(ng-if='newChallenge')
form(ng-submit='save(newChallenge)')
div
input.btn.btn-success(type='submit', value='Save')
input.btn.btn-danger(type='button', ng-click='discard()', value='Discard')
select(ng-model='newChallenge.group', ng-required='required', name='Group', ng-options='g._id as g.name for g in groups')
.challenge-options
input.option-content(type='text', ng-model='newChallenge.name', placeholder='Challenge Title', required='required')
script(type='text/ng-template', id='partials/options.challenges.html')
.row-fluid
.span2.well
h4 Filters
ul
li(ng-repeat='group in groups')
input(type='checkbox', ng-model='search.group')
| {{group.name}}
li
input(type='checkbox', ng-model='search.members')
| Subscribed (TODO)
li
input(type='checkbox', ng-model='search.members')
| Available (TODO)
.span10
// Creation form
a.btn.btn-success(ng-click='create()') Create Challenge
.create-challenge-from(ng-if='newChallenge')
form(ng-submit='save(newChallenge)')
div
input.btn.btn-success(type='submit', value='Save')
input.btn.btn-danger(type='button', ng-click='discard()', value='Discard')
select(ng-model='newChallenge.group', ng-required='required', name='Group', ng-options='g._id as g.name for g in groups')
.challenge-options
input.option-content(type='text', ng-model='newChallenge.name', placeholder='Challenge Title', required='required')
habitrpg-tasks(main=false, obj='newChallenge')
habitrpg-tasks(main=false, obj='newChallenge')
// Challenges list
.accordion-group(ng-repeat='challenge in challenges | filter:search', ng-init='challenge._locked=true')
.accordion-heading
ul.pull-right.challenge-accordion-header-specs
li {{challenge.members.length}} Subscribers
li(ng-show='challenge.prize')
// prize
table(ng-show='challenge.prize')
tr
td {{challenge.prize}}
td
span.Pet_Currency_Gem1x
td Prize
li
// subscribe / unsubscribe
a.btn.btn-small.btn-danger(ng-show='indexOf(challenge.members, user._id)', ng-click='clickUnsubscribe(challenge, $event)')
i.icon-ban-circle
| Unsubscribe
a.btn.btn-small.btn-success(ng-hide='indexOf(challenge.members, user._id)', ng-click='challenge.$join()')
i.icon-ok
| Subscribe
a.accordion-toggle(data-toggle='collapse', data-target='#accordion-challenge-{{challenge._id}}') {{challenge.name}} (by {{challenge.leader.name}})
.accordion-body.collapse(id='accordion-challenge-{{challenge._id}}')
.accordion-inner
// Edit button
ul.unstyled()
li(ng-show='challenge.leader==user._id && challenge._locked')
button.btn.btn-default(ng-click='challenge._locked = false') Edit
li(ng-hide='challenge._locked')
button.btn.btn-primary(ng-click='save(challenge)') Save
button.btn.btn-danger(ng-click='delete(challenge)') Delete
button.btn.btn-default(ng-click='challenge._locked=true') Cancel
// Challenges list
.accordion-group(ng-repeat='challenge in challenges | filter:search', ng-init='challenge._locked=true')
.accordion-heading
ul.pull-right.challenge-accordion-header-specs
li {{challenge.members.length}} Subscribers
li(ng-show='challenge.prize')
// prize
table(ng-show='challenge.prize')
tr
td {{challenge.prize}}
td
span.Pet_Currency_Gem1x
td Prize
li
// subscribe / unsubscribe
a.btn.btn-small.btn-danger(ng-show='indexOf(challenge.members, user._id)', ng-click='clickUnsubscribe(challenge, $event)')
i.icon-ban-circle
| Unsubscribe
a.btn.btn-small.btn-success(ng-hide='indexOf(challenge.members, user._id)', ng-click='challenge.$join()')
i.icon-ok
| Subscribe
a.accordion-toggle(data-toggle='collapse', data-target='#accordion-challenge-{{challenge._id}}') {{challenge.name}} (by {{challenge.leader.name}})
.accordion-body.collapse(id='accordion-challenge-{{challenge._id}}')
.accordion-inner
// Edit button
ul.unstyled()
li(ng-show='challenge.leader==user._id && challenge._locked')
button.btn.btn-default(ng-click='challenge._locked = false') Edit
li(ng-hide='challenge._locked')
button.btn.btn-primary(ng-click='save(challenge)') Save
button.btn.btn-danger(ng-click='delete(challenge)') Delete
button.btn.btn-default(ng-click='challenge._locked=true') Cancel
div(ng-hide='challenge._locked')
.-options
input.option-content(type='text', ng-model='challenge.name')
textarea.option-content(cols='3', placeholder='Description', ng-model='challenge.description')
// <input type=number class='option-content' placeholder='Gems Prize' value={@challenge.prize} />
hr
div(ng-hide='challenge._locked')
.-options
input.option-content(type='text', ng-model='challenge.name')
textarea.option-content(cols='3', placeholder='Description', ng-model='challenge.description')
// <input type=number class='option-content' placeholder='Gems Prize' value={@challenge.prize} />
hr
div(ng-if='challenge.description') {{challenge.description}}
habitrpg-tasks(obj='challenge', main=false)
h3 Statistics
div(ng-repeat='member in challenge.members', ng-init='member._locked = true')
h4 {{member.profile.name}}
habitrpg-tasks(main=false, obj='member')
div(ng-if='challenge.description') {{challenge.description}}
habitrpg-tasks(obj='challenge', main=false)
h3 Statistics
div(ng-repeat='member in challenge.members', ng-init='member._locked = true')
h4 {{member.profile.name}}
habitrpg-tasks(main=false, obj='member')

View File

@@ -1,66 +1,79 @@
// 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
ul.nav.nav-tabs
li.active
a(data-target='#groups-party', data-toggle='tab') Party
li
a(data-target='#groups-guilds', data-toggle='tab', ng-click='fetchGuilds()') Guilds
script(type='text/ng-template', id='partials/options.groups.tavern.html')
include ./tavern
.tab-content(ng-controller='PartyCtrl')
#groups-party.tab-pane.active
div(ng-show='group._id')
script(type='text/ng-template', id='partials/options.groups.party.html')
div(ng-show='group._id')
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()') 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
script(type='text/ng-template', id='partials/options.groups.guilds.html')
ul.nav.nav-tabs
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(invitation)') Accept
a.btn.btn-danger(ng-click='reject(invitation)') 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
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()') 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')
ul.nav.nav-tabs
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(invitation)') Accept
a.btn.btn-danger(ng-click='reject(invitation)') 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
.tab-pane#groups-create-guild
include ./create-group
script(type='text/ng-template', id='partials/options.groups.html')
ul.nav.nav-tabs
li(ng-class="{ active: $state.includes('options.groups.tavern') }")
a(ui-sref='options.groups.tavern')
i.icon-eye-close
| Tavern
li(ng-class="{ active: $state.includes('options.groups.party') }")
a(ui-sref='options.groups.party')
| Party
li(ng-class="{ active: $state.includes('options.groups.guilds') }")
a(ui-sref='options.groups.guilds')
| Guilds
.tab-content
.tab-pane.active
div(ui-view)

View File

@@ -1,4 +1,4 @@
.row-fluid(ng-controller='TavernCtrl')
.row-fluid
.span4
.tavern-pane
table

View File

@@ -1,64 +1,37 @@
script(id='templates/habitrpg-options.html', type="text/ng-template")
include ./profile
include ./groups/index
include ./challenges
include ./inventory/index
include ./settings
script(id='partials/options.html', type="text/ng-template")
.grid
.module.full-width
span.option-box.pull-right.wallet
include ../shared/gems
ul.nav.nav-tabs
li.active
a(data-toggle='tab', data-target='#profile-tab')
li(ng-class="{ active: $state.includes('options.profile') }")
a(ui-sref='options.profile')
i.icon-user
| Profile
li
a(data-toggle='tab',data-target='#groups-tab', ng-click='fetchParty()')
li(ng-class="{ active: $state.includes('options.groups') }")
a(ui-sref='options.groups')
i.icon-heart
| Groups
li(ng-show='user.flags.dropsEnabled')
a(data-toggle='tab',data-target='#inventory-tab')
li(ng-class="{ active: $state.includes('options.inventory') }", ng-if='user.flags.dropsEnabled')
a(ui-sref='options.inventory')
i.icon-gift
| Inventory
li(ng-show='user.flags.dropsEnabled')
a(data-toggle='tab',data-target='#stable-tab')
i.icon-leaf
| Stable
li
a(data-toggle='tab',data-target='#tavern-tab', ng-click='fetchTavern()')
i.icon-eye-close
| Tavern
li
a(data-toggle='tab',data-target='#achievements-tab')
i.icon-certificate
| Achievements
li
a(data-toggle='tab',data-target='#challenges-tab')
li(ng-class="{ active: $state.includes('options.challenges') }")
a(ui-sref='options.challenges')
i.icon-bullhorn
| Challenges
li
a(data-toggle='tab',data-target='#settings-tab')
li(ng-class="{ active: $state.includes('options.settings') }")
a(ui-sref='options.settings')
i.icon-wrench
| Settings
.tab-content
.tab-pane.active#profile-tab
include ./profile
.tab-pane#groups-tab
include ./groups/index
.tab-pane#inventory-tab
include ./inventory
.tab-pane#stable-tab
include ./pets
.tab-pane#tavern-tab
include ./groups/tavern
.tab-pane#achievements-tab(ng-controller='UserCtrl')
include ../shared/profiles/achievements
.tab-pane#challenges-tab
include ./challenges
.tab-pane#settings-tab
include ./settings
.tab-pane.active
div(ui-view)

View File

@@ -1,54 +0,0 @@
.row-fluid(ng-controller='InventoryCtrl')
.span6.border-right
h2 Inventory
p.well Combine eggs with hatching potions to make pets by clicking an egg and then a potion. Sell unwanted drops to Alexander the Merchant.
menu.inventory-list(type='list')
li.customize-menu
menu.pets-menu(label='Eggs ({{userEggs.length}})')
p(ng-show='userEggs.length < 1') You don't have any eggs yet.
div(ng-repeat='egg in userEggs track by $index')
button.customize-option(tooltip='{{egg.text}}', ng-click='chooseEgg(egg, $index)', class='Pet_Egg_{{egg.name}}', ng-class='selectableInventory(egg, selectedPotion.name, $index)')
p {{egg.text}}
li.customize-menu
menu.hatchingPotion-menu(label='Hatching Potions ({{userHatchingPotions.length}})')
p(ng-show='userHatchingPotions.length < 1') You don't have any hatching potions yet.
div(ng-repeat='hatchingPotion in userHatchingPotions track by $index')
button.customize-option(tooltip='{{hatchingPotion}}', ng-click='choosePotion(hatchingPotion, $index)', class='Pet_HatchingPotion_{{hatchingPotion}}', ng-class='selectableInventory(selectedEgg, hatchingPotion, $index)')
p {{hatchingPotion}}
.span6
h2 Market
.row-fluid(ng-controller='MarketCtrl')
table.NPC-Alex-container
tr
td
.NPC-Alex.pull-left
td
.popover.static-popover.fade.right.in
.arrow
h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/523661924') Alexander the Merchant
.popover-content
p
| Welcome to the Market. Dying to get that particular pet you're after, but don't want to wait for it to drop? Buy it here! If you have unwanted drops, sell them to me.
p
button.btn.btn-primary(ng-show='selectedEgg', ng-click='sellInventory()')
| Sell {{selectedEgg.name}} for {{selectedEgg.value}} GP
button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()')
| Sell {{selectedPotion.name}} for {{selectedPotion.value}} GP
menu.inventory-list(type='list')
li.customize-menu
menu.pets-menu(label='Eggs')
div(ng-repeat='egg in eggs track by $index')
button.customize-option(tooltip='{{egg.text}} - {{egg.value}} Gem(s)', ng-click='buy("egg", egg)', class='Pet_Egg_{{egg.name}}')
p {{egg.text}}
li.customize-menu
menu.pets-menu(label='Hatching Potions')
div(ng-repeat='hatchingPotion in hatchingPotions track by $index')
button.customize-option(tooltip='{{hatchingPotion.text}} - {{hatchingPotion.value}} Gem(s)', ng-click='buy("hatchingPotion", hatchingPotion)', class='Pet_HatchingPotion_{{hatchingPotion.name}}')
p {{hatchingPotion.text}}

View File

@@ -0,0 +1,15 @@
include ./inventory
include ./stable
script(type='text/ng-template', id='partials/options.inventory.html')
ul.nav.nav-tabs
li(ng-class="{ active: $state.includes('options.inventory.inventory') }")
a(ui-sref='options.inventory.inventory')
| Inventory
li(ng-class="{ active: $state.includes('options.inventory.stable') }")
a(ui-sref='options.inventory.stable')
| Stable
.tab-content
.tab-pane.active
div(ui-view)

View File

@@ -0,0 +1,55 @@
script(type='text/ng-template', id='partials/options.inventory.inventory.html')
.row-fluid(ng-controller='InventoryCtrl')
.span6.border-right
h2 Inventory
p.well Combine eggs with hatching potions to make pets by clicking an egg and then a potion. Sell unwanted drops to Alexander the Merchant.
menu.inventory-list(type='list')
li.customize-menu
menu.pets-menu(label='Eggs ({{userEggs.length}})')
p(ng-show='userEggs.length < 1') You don't have any eggs yet.
div(ng-repeat='egg in userEggs track by $index')
button.customize-option(tooltip='{{egg.text}}', ng-click='chooseEgg(egg, $index)', class='Pet_Egg_{{egg.name}}', ng-class='selectableInventory(egg, selectedPotion.name, $index)')
p {{egg.text}}
li.customize-menu
menu.hatchingPotion-menu(label='Hatching Potions ({{userHatchingPotions.length}})')
p(ng-show='userHatchingPotions.length < 1') You don't have any hatching potions yet.
div(ng-repeat='hatchingPotion in userHatchingPotions track by $index')
button.customize-option(tooltip='{{hatchingPotion}}', ng-click='choosePotion(hatchingPotion, $index)', class='Pet_HatchingPotion_{{hatchingPotion}}', ng-class='selectableInventory(selectedEgg, hatchingPotion, $index)')
p {{hatchingPotion}}
.span6
h2 Market
.row-fluid(ng-controller='MarketCtrl')
table.NPC-Alex-container
tr
td
.NPC-Alex.pull-left
td
.popover.static-popover.fade.right.in
.arrow
h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/523661924') Alexander the Merchant
.popover-content
p
| Welcome to the Market. Dying to get that particular pet you're after, but don't want to wait for it to drop? Buy it here! If you have unwanted drops, sell them to me.
p
button.btn.btn-primary(ng-show='selectedEgg', ng-click='sellInventory()')
| Sell {{selectedEgg.name}} for {{selectedEgg.value}} GP
button.btn.btn-primary(ng-show='selectedPotion', ng-click='sellInventory()')
| Sell {{selectedPotion.name}} for {{selectedPotion.value}} GP
menu.inventory-list(type='list')
li.customize-menu
menu.pets-menu(label='Eggs')
div(ng-repeat='egg in eggs track by $index')
button.customize-option(tooltip='{{egg.text}} - {{egg.value}} Gem(s)', ng-click='buy("egg", egg)', class='Pet_Egg_{{egg.name}}')
p {{egg.text}}
li.customize-menu
menu.pets-menu(label='Hatching Potions')
div(ng-repeat='hatchingPotion in hatchingPotions track by $index')
button.customize-option(tooltip='{{hatchingPotion.text}} - {{hatchingPotion.value}} Gem(s)', ng-click='buy("hatchingPotion", hatchingPotion)', class='Pet_HatchingPotion_{{hatchingPotion.name}}')
p {{hatchingPotion.text}}

View File

@@ -0,0 +1,30 @@
script(type='text/ng-template', id='partials/options.inventory.stable.html')
.stable(ng-controller='PetsCtrl')
.NPC-Matt
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
.arrow
h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch') Matt Boch
.popover-content
p
| Welcome to the Stable! I'm Matt, the beast master. Choose a pet here to adventure at your side - they aren't much help yet, but I forsee a time when they're able to
a(href='https://trello.com/card/mounts/50e5d3684fe3a7266b0036d6/221') grow into powerful steeds
| ! Until that day,
a(target='_blank', href='https://f.cloud.github.com/assets/2374703/164631/3ed5fa6c-78cd-11e2-8743-f65ac477b55e.png') have a look-see
| at all the pets you can collect.
h4 {{userPets.length}} / {{totalPets}} Pets Found
menu.pets(type='list')
li.customize-menu(ng-repeat='pet in pets')
menu
div(ng-repeat='potion in hatchingPotions', tooltip='{{potion.name}} {{pet.name}}')
button(class="pet-button Pet-{{pet.name}}-{{potion.name}}", ng-show='hasPet(pet.name, potion.name)', ng-class="{active: isCurrentPet(pet.name, potion.name)}", ng-click='choosePet(pet.name, potion.name)')
button(class="pet-button pet-not-owned", ng-hide='hasPet(pet.name, potion.name)')
img(src='/bower_components/habitrpg-shared/img/PixelPaw.png')
h4 Rare Pets
menu
div(ng-if='hasPet("Wolf", "Veteran")')
button(class="pet-button Pet-Wolf-Veteran", ng-class='{active: isCurrentPet("Wolf", "Veteran")}', ng-click='choosePet("Wolf", "Veteran")', tooltip='Veteran Wolf')
div(ng-if='hasPet("Wolf", "Cerberus")')
button(class="pet-button Pet-Wolf-Cerberus", ng-class='{active: isCurrentPet("Wolf", "Cerberus")}', ng-click='choosePet("Wolf", "Cerberus")', tooltip='Cerberus Pup')

View File

@@ -1,29 +0,0 @@
.stable(ng-controller='PetsCtrl')
.NPC-Matt
.popover.static-popover.fade.right.in(style='max-width: 550px; margin-left: 10px;')
.arrow
h3.popover-title
a(target='_blank', href='http://www.kickstarter.com/profile/mattboch') Matt Boch
.popover-content
p
| Welcome to the Stable! I'm Matt, the beast master. Choose a pet here to adventure at your side - they aren't much help yet, but I forsee a time when they're able to
a(href='https://trello.com/card/mounts/50e5d3684fe3a7266b0036d6/221') grow into powerful steeds
| ! Until that day,
a(target='_blank', href='https://f.cloud.github.com/assets/2374703/164631/3ed5fa6c-78cd-11e2-8743-f65ac477b55e.png') have a look-see
| at all the pets you can collect.
h4 {{userPets.length}} / {{totalPets}} Pets Found
menu.pets(type='list')
li.customize-menu(ng-repeat='pet in pets')
menu
div(ng-repeat='potion in hatchingPotions', tooltip='{{potion.name}} {{pet.name}}')
button(class="pet-button Pet-{{pet.name}}-{{potion.name}}", ng-show='hasPet(pet.name, potion.name)', ng-class="{active: isCurrentPet(pet.name, potion.name)}", ng-click='choosePet(pet.name, potion.name)')
button(class="pet-button pet-not-owned", ng-hide='hasPet(pet.name, potion.name)')
img(src='/bower_components/habitrpg-shared/img/PixelPaw.png')
h4 Rare Pets
menu
div(ng-if='hasPet("Wolf", "Veteran")')
button(class="pet-button Pet-Wolf-Veteran", ng-class='{active: isCurrentPet("Wolf", "Veteran")}', ng-click='choosePet("Wolf", "Veteran")', tooltip='Veteran Wolf')
div(ng-if='hasPet("Wolf", "Cerberus")')
button(class="pet-button Pet-Wolf-Cerberus", ng-class='{active: isCurrentPet("Wolf", "Cerberus")}', ng-click='choosePet("Wolf", "Cerberus")', tooltip='Cerberus Pup')

View File

@@ -1,128 +1,145 @@
.row-fluid(ng-controller='UserCtrl')
// ---- Customize -----
.span4.border-right
menu(type='list')
// gender
li.customize-menu
menu(label='Head')
menu
button.m_head_0.customize-option(type='button', ng-click='set("preferences.gender","m")')
button.f_head_0.customize-option(type='button', ng-click='set("preferences.gender","f")')
label.checkbox
input(type='checkbox', ng-model='user.preferences.showHelm', ng-change='toggleHelm(user.preferences.showHelm)')
| Show Helm
hr
// hair
li.customize-menu
menu(label='Hair')
button(class='{{user.preferences.gender}}_hair_blond customize-option', type='button', ng-click='set("preferences.hair","blond")')
button(class='{{user.preferences.gender}}_hair_black customize-option', type='button', ng-click='set("preferences.hair","black")')
button(class='{{user.preferences.gender}}_hair_brown customize-option', type='button', ng-click='set("preferences.hair","brown")')
button(class='{{user.preferences.gender}}_hair_white customize-option', type='button', ng-click='set("preferences.hair","white")')
button(class='{{user.preferences.gender}}_hair_red customize-option', type='button', ng-click='set("preferences.hair","red")')
hr
// skin
li.customize-menu
menu(label='Basic Skins')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_asian', ng-click='set("preferences.skin","asian")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_white', ng-click='set("preferences.skin","white")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_ea8349', ng-click='set("preferences.skin","ea8349")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_c06534', ng-click='set("preferences.skin","c06534")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_98461a', ng-click='set("preferences.skin","98461a")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_black', ng-click='set("preferences.skin","black")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_dead', ng-click='set("preferences.skin","dead")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_orc', ng-click='set("preferences.skin","orc")')
// Rainbow Skin
h5.
Rainbow Skins - 2<span class="Pet_Currency_Gem1x inline-gems"/>/skin
//menu(label='Rainbow Skins (2G / skin)')
menu
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_eb052b', ng-class='{locked: !user.purchased.skin.eb052b}', ng-click='unlock("skin.eb052b")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_f69922', ng-class='{locked: !user.purchased.skin.f69922}', ng-click='unlock("skin.f69922")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_f5d70f', ng-class='{locked: !user.purchased.skin.f5d70f}', ng-click='unlock("skin.f5d70f")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_0ff591', ng-class='{locked: !user.purchased.skin.0ff591}', ng-click='unlock("skin.0ff591")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_2b43f6', ng-class='{locked: !user.purchased.skin.2b43f6}', ng-click='unlock("skin.2b43f6")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_d7a9f7', ng-class='{locked: !user.purchased.skin.d7a9f7}', ng-click='unlock("skin.d7a9f7")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_800ed0', ng-class='{locked: !user.purchased.skin.800ed0}', ng-click='unlock("skin.800ed0")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_rainbow', ng-class='{locked: !user.purchased.skin.rainbow}', ng-click='unlock("skin.rainbow")')
button.btn.btn-small.btn-primary(ng-hide='user.purchased.skin.eb052b && user.purchased.skin.f69922 && user.purchased.skin.f5d70f && user.purchased.skin.0ff591 && user.purchased.skin.2b43f6 && user.purchased.skin.d7a9f7 && user.purchased.skin.800ed0 && user.purchased.skin.rainbow', ng-click='unlock(["skin.eb052b", "skin.f69922", "skin.f5d70f", "skin.0ff591", "skin.2b43f6", "skin.d7a9f7", "skin.800ed0", "skin.rainbow"])') Unlock Set - 5<span class="Pet_Currency_Gem1x inline-gems"/>
// Special Events
div.well.limited-edition
.label.label-info.pull-right(popover='Available for purchase until November 10th (but permanently in your options if purchased).', popover-title='Limited Edition', popover-placement='right', popover-trigger='mouseenter')
| Limited Edition&nbsp;
i.icon.icon-question-sign
h5.
Spooky Skins - 2<span class="Pet_Currency_Gem1x inline-gems"/>/skin
//menu(label='Spooky Skins (2 Gems / skin)')
menu
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_monster', ng-class='{locked: !user.purchased.skin.monster}', ng-click='unlock("skin.monster")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_pumpkin', ng-class='{locked: !user.purchased.skin.pumpkin}', ng-click='unlock("skin.pumpkin")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_skeleton', ng-class='{locked: !user.purchased.skin.skeleton}', ng-click='unlock("skin.skeleton")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_zombie', ng-class='{locked: !user.purchased.skin.zombie}', ng-click='unlock("skin.zombie")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_ghost', ng-class='{locked: !user.purchased.skin.ghost}', ng-click='unlock("skin.ghost")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_shadow', ng-class='{locked: !user.purchased.skin.shadow}', ng-click='unlock("skin.shadow")')
button.btn.btn-small.btn-primary(ng-hide='user.purchased.skin.monster && user.purchased.skin.pumpkin && user.purchased.skin.skeleton && user.purchased.skin.zombie && user.purchased.skin.ghost && user.purchased.skin.shadow', ng-click='unlock(["skin.monster", "skin.pumpkin", "skin.skeleton", "skin.zombie", "skin.ghost", "skin.shadow"])') Unlock Set - 5<span class="Pet_Currency_Gem1x inline-gems"/>
menu(ng-show='user.preferences.gender=="f"', type='list')
script(id='partials/options.profile.avatar.html', type='text/ng-template')
.row-fluid
.span4.border-right
menu(type='list')
// body-type
li.customize-menu
menu(label='Clothing')
button.f_armor_0_v1.customize-option(type='button', ng-click='set("preferences.armorSet","v1")')
button.f_armor_0_v2.customize-option(type='button', ng-click='set("preferences.armorSet","v2")')
menu(label='Head')
menu
button.m_head_0.customize-option(type='button', ng-click='set("preferences.gender","m")')
button.f_head_0.customize-option(type='button', ng-click='set("preferences.gender","f")')
label.checkbox
input(type='checkbox', ng-model='user.preferences.showHelm', ng-change='toggleHelm(user.preferences.showHelm)')
| Show Helm
// ------ Stats ------
.span4.border-right
include ../shared/profiles/stats
menu(ng-show='user.preferences.gender=="f"', type='list')
li.customize-menu
menu(label='Clothing')
button.f_armor_0_v1.customize-option(type='button', ng-click='set("preferences.armorSet","v1")')
button.f_armor_0_v2.customize-option(type='button', ng-click='set("preferences.armorSet","v2")')
// ------- Edit -------
.span4
button.btn.btn-default(ng-click='_editing.profile = true', ng-show='!_editing.profile') Edit
button.btn.btn-primary(ng-click='save()', ng-show='_editing.profile') Save
div(ng-show='!_editing.profile')
h4 Display Name
span(ng-show='profile.profile.name') {{profile.profile.name}}
span.muted(ng-hide='profile.profile.name') - None -
.span4.border-right
// hair
li.customize-menu
menu(label='Hair')
button(class='{{user.preferences.gender}}_hair_blond customize-option', type='button', ng-click='set("preferences.hair","blond")')
button(class='{{user.preferences.gender}}_hair_black customize-option', type='button', ng-click='set("preferences.hair","black")')
button(class='{{user.preferences.gender}}_hair_brown customize-option', type='button', ng-click='set("preferences.hair","brown")')
button(class='{{user.preferences.gender}}_hair_white customize-option', type='button', ng-click='set("preferences.hair","white")')
button(class='{{user.preferences.gender}}_hair_red customize-option', type='button', ng-click='set("preferences.hair","red")')
h4 Photo
img(ng-show='profile.profile.imageUrl', ng-src='{{profile.profile.imageUrl}}')
span.muted(ng-hide='profile.profile.imageUrl') - None -
.span4.border-right
// skin
li.customize-menu
menu(label='Basic Skins')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_asian', ng-click='set("preferences.skin","asian")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_white', ng-click='set("preferences.skin","white")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_ea8349', ng-click='set("preferences.skin","ea8349")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_c06534', ng-click='set("preferences.skin","c06534")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_98461a', ng-click='set("preferences.skin","98461a")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_black', ng-click='set("preferences.skin","black")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_dead', ng-click='set("preferences.skin","dead")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_orc', ng-click='set("preferences.skin","orc")')
h4 Blurb
markdown(ng-show='profile.profile.blurb', ng-model='profile.profile.blurb')
span.muted(ng-hide='profile.profile.blurb') - None -
//{{profile.profile.blurb | linky:'_blank'}}
// Rainbow Skin
h5.
Rainbow Skins - 2<span class="Pet_Currency_Gem1x inline-gems"/>/skin
//menu(label='Rainbow Skins (2G / skin)')
menu
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_eb052b', ng-class='{locked: !user.purchased.skin.eb052b}', ng-click='unlock("skin.eb052b")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_f69922', ng-class='{locked: !user.purchased.skin.f69922}', ng-click='unlock("skin.f69922")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_f5d70f', ng-class='{locked: !user.purchased.skin.f5d70f}', ng-click='unlock("skin.f5d70f")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_0ff591', ng-class='{locked: !user.purchased.skin.0ff591}', ng-click='unlock("skin.0ff591")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_2b43f6', ng-class='{locked: !user.purchased.skin.2b43f6}', ng-click='unlock("skin.2b43f6")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_d7a9f7', ng-class='{locked: !user.purchased.skin.d7a9f7}', ng-click='unlock("skin.d7a9f7")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_800ed0', ng-class='{locked: !user.purchased.skin.800ed0}', ng-click='unlock("skin.800ed0")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_rainbow', ng-class='{locked: !user.purchased.skin.rainbow}', ng-click='unlock("skin.rainbow")')
button.btn.btn-small.btn-primary(ng-hide='user.purchased.skin.eb052b && user.purchased.skin.f69922 && user.purchased.skin.f5d70f && user.purchased.skin.0ff591 && user.purchased.skin.2b43f6 && user.purchased.skin.d7a9f7 && user.purchased.skin.800ed0 && user.purchased.skin.rainbow', ng-click='unlock(["skin.eb052b", "skin.f69922", "skin.f5d70f", "skin.0ff591", "skin.2b43f6", "skin.d7a9f7", "skin.800ed0", "skin.rainbow"])') Unlock Set - 5<span class="Pet_Currency_Gem1x inline-gems"/>
h4 Websites
ul(ng-show='profile.profile.websites.length > 0')
// TODO let's remove links eventually, since we can do markdown on profiles
li(ng-repeat='website in profile.profile.websites')
a(target='_blank', ng-href='{{website}}') {{website}}
span.muted(ng-hide='profile.profile.websites.length > 0') - None -
// Special Events
div.well.limited-edition
.label.label-info.pull-right(popover='Available for purchase until November 10th (but permanently in your options if purchased).', popover-title='Limited Edition', popover-placement='right', popover-trigger='mouseenter')
| Limited Edition&nbsp;
i.icon.icon-question-sign
h5.
Spooky Skins - 2<span class="Pet_Currency_Gem1x inline-gems"/>/skin
//menu(label='Spooky Skins (2 Gems / skin)')
menu
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_monster', ng-class='{locked: !user.purchased.skin.monster}', ng-click='unlock("skin.monster")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_pumpkin', ng-class='{locked: !user.purchased.skin.pumpkin}', ng-click='unlock("skin.pumpkin")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_skeleton', ng-class='{locked: !user.purchased.skin.skeleton}', ng-click='unlock("skin.skeleton")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_zombie', ng-class='{locked: !user.purchased.skin.zombie}', ng-click='unlock("skin.zombie")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_ghost', ng-class='{locked: !user.purchased.skin.ghost}', ng-click='unlock("skin.ghost")')
button.customize-option(type='button', class='{{user.preferences.gender}}_skin_shadow', ng-class='{locked: !user.purchased.skin.shadow}', ng-click='unlock("skin.shadow")')
button.btn.btn-small.btn-primary(ng-hide='user.purchased.skin.monster && user.purchased.skin.pumpkin && user.purchased.skin.skeleton && user.purchased.skin.zombie && user.purchased.skin.ghost && user.purchased.skin.shadow', ng-click='unlock(["skin.monster", "skin.pumpkin", "skin.skeleton", "skin.zombie", "skin.ghost", "skin.shadow"])') Unlock Set - 5<span class="Pet_Currency_Gem1x inline-gems"/>
div.whatever-options(ng-show='_editing.profile')
// TODO use photo-upload instead: https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/xMmADvxBOak
.control-group.option-large
label.control-label Display Name
input.option-content(type='text', placeholder='Full Name', ng-model='editingProfile.name')
.control-group.option-large
label.control-label Photo Url
input.option-content(type='url', ng-model='editingProfile.imageUrl', placeholder='Image Url')
.control-group.option-large
label.control-label Blurb
textarea.option-content(style='height:15em;', placeholder='Blurb', ng-model='editingProfile.blurb')
include ../shared/formatting-help
.control-group.option-large
label.control-label Websites
form(ng-submit='addWebsite()')
input.option-content(type='url', ng-model='_newWebsite', placeholder='Add Website')
ul
// would prefer if there were and index in #each, instead using data-website to search with indexOf
li(ng-repeat='website in editingProfile.websites')
| {{website}}
a(ng-click='removeWebsite($index)')
i.icon-remove
script(id='partials/options.profile.stats.html', type='text/ng-template')
.row-fluid
.span6.border-right
include ../shared/profiles/stats
.span6.border-right
include ../shared/profiles/achievements
script(id='partials/options.profile.profile.html', type='text/ng-template')
button.btn.btn-default(ng-click='_editing.profile = true', ng-show='!_editing.profile') Edit
button.btn.btn-primary(ng-click='save()', ng-show='_editing.profile') Save
div(ng-show='!_editing.profile')
h4 Display Name
span(ng-show='profile.profile.name') {{profile.profile.name}}
span.muted(ng-hide='profile.profile.name') - None -
h4 Photo
img(ng-show='profile.profile.imageUrl', ng-src='{{profile.profile.imageUrl}}')
span.muted(ng-hide='profile.profile.imageUrl') - None -
h4 Blurb
markdown(ng-show='profile.profile.blurb', ng-model='profile.profile.blurb')
span.muted(ng-hide='profile.profile.blurb') - None -
//{{profile.profile.blurb | linky:'_blank'}}
h4 Websites
ul(ng-show='profile.profile.websites.length > 0')
// TODO let's remove links eventually, since we can do markdown on profiles
li(ng-repeat='website in profile.profile.websites')
a(target='_blank', ng-href='{{website}}') {{website}}
span.muted(ng-hide='profile.profile.websites.length > 0') - None -
div.whatever-options(ng-show='_editing.profile')
// TODO use photo-upload instead: https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/xMmADvxBOak
.control-group.option-large
label.control-label Display Name
input.option-content(type='text', placeholder='Full Name', ng-model='editingProfile.name')
.control-group.option-large
label.control-label Photo Url
input.option-content(type='url', ng-model='editingProfile.imageUrl', placeholder='Image Url')
.control-group.option-large
label.control-label Blurb
textarea.option-content(style='height:15em;', placeholder='Blurb', ng-model='editingProfile.blurb')
br
include ../shared/formatting-help
.control-group.option-large
label.control-label Websites
form(ng-submit='addWebsite()')
input.option-content(type='url', ng-model='_newWebsite', placeholder='Add Website')
ul
// would prefer if there were and index in #each, instead using data-website to search with indexOf
li(ng-repeat='website in editingProfile.websites')
| {{website}}
a(ng-click='removeWebsite($index)')
i.icon-remove
script(id='partials/options.profile.html', type="text/ng-template")
ul.nav.nav-tabs
li(ng-class="{ active: $state.includes('options.profile.avatar') }")
a(ui-sref='options.profile.avatar')
| Avatar
li(ng-class="{ active: $state.includes('options.profile.stats') }")
a(ui-sref='options.profile.stats')
| Stats & Achievements
li(ng-class="{ active: $state.includes('options.profile.profile') }")
a(ui-sref='options.profile.profile')
| Profile
.tab-content
.tab-pane.active
div(ui-view)

View File

@@ -1,43 +1,44 @@
.row-fluid(ng-controller='SettingsCtrl')
.personal-options.span6.border-right
h2 Settings
h4 Custom Day Start
.option-group.option-short
input.option-content.option-time(type='number', min='0', max='24', ng-model='user.preferences.dayStart', ng-change='saveDayStart()')
span.input-suffix :00 (24h clock)
div
small
| Habit defaults to check and reset your dailies at midnight in your time zone each day. You can customize the hour here (enter a number between 0 and 24).
hr
h4 Misc
button.btn(ng-hide='user.preferences.hideHeader', ng-click='set("preferences.hideHeader",true)') Hide Header
button.btn(ng-show='user.preferences.hideHeader', ng-click='set("preferences.hideHeader",false)') Show Header
button.btn(ng-click='showTour()') Show Tour
button.btn(ng-click='showBailey()') Show Bailey
div(ng-show='user.auth.local')
script(type='text/ng-template', id='partials/options.settings.html')
.row-fluid
.personal-options.span6.border-right
h2 Settings
h4 Custom Day Start
.option-group.option-short
input.option-content.option-time(type='number', min='0', max='24', ng-model='user.preferences.dayStart', ng-change='saveDayStart()')
span.input-suffix :00 (24h clock)
div
small
| Habit defaults to check and reset your dailies at midnight in your time zone each day. You can customize the hour here (enter a number between 0 and 24).
hr
h4 Change Password
form(ng-submit='changePassword(changePass)', ng-show='user.auth.local')
.control-group
input(type='password', placeholder='Old Password', ng-model='changePass.oldPassword', required)
.control-group
input(type='password', placeholder='New Password', ng-model='changePass.newPassword', required)
.control-group
input(type='password', placeholder='Confirm New Password', ng-model='changePass.confirmNewPassword', required)
input.btn(type='submit', value='Submit')
h4 Misc
button.btn(ng-hide='user.preferences.hideHeader', ng-click='set("preferences.hideHeader",true)') Hide Header
button.btn(ng-show='user.preferences.hideHeader', ng-click='set("preferences.hideHeader",false)') Show Header
button.btn(ng-click='showTour()') Show Tour
button.btn(ng-click='showBailey()') Show Bailey
hr
h4 Danger Zone
a.btn.btn-danger(ng-click='modals.reset = true', tooltip='Resets your entire account (dangerous).') Reset
a.btn.btn-danger(ng-click='modals.restore = true', tooltip='Restores attributes to your character.') Restore
a.btn.btn-danger(ng-click='modals.delete = true', tooltip='Delete your account.') Delete
.span6
h2 API
small Copy these for use in third party applications.
h6 User ID
pre.prettyprint {{user.id}}
h6 API Token
pre.prettyprint {{user.apiToken}}
h6 QR Code
img(src='https://chart.googleapis.com/chart?cht=qr&chs=200x200&chl=%7Baddress%3A%22https%3A%2F%2Fhabitrpg.com%22%2Cuser%3A%22{{user.id}}%22%2Ckey%3A%22{{user.apiToken}}%22%7D,&choe=UTF-8&chld=L', alt='qrcode')
div(ng-show='user.auth.local')
hr
h4 Change Password
form(ng-submit='changePassword(changePass)', ng-show='user.auth.local')
.control-group
input(type='password', placeholder='Old Password', ng-model='changePass.oldPassword', required)
.control-group
input(type='password', placeholder='New Password', ng-model='changePass.newPassword', required)
.control-group
input(type='password', placeholder='Confirm New Password', ng-model='changePass.confirmNewPassword', required)
input.btn(type='submit', value='Submit')
hr
h4 Danger Zone
a.btn.btn-danger(ng-click='modals.reset = true', tooltip='Resets your entire account (dangerous).') Reset
a.btn.btn-danger(ng-click='modals.restore = true', tooltip='Restores attributes to your character.') Restore
a.btn.btn-danger(ng-click='modals.delete = true', tooltip='Delete your account.') Delete
.span6
h2 API
small Copy these for use in third party applications.
h6 User ID
pre.prettyprint {{user.id}}
h6 API Token
pre.prettyprint {{user.apiToken}}
h6 QR Code
img(src='https://chart.googleapis.com/chart?cht=qr&chs=200x200&chl=%7Baddress%3A%22https%3A%2F%2Fhabitrpg.com%22%2Cuser%3A%22{{user.id}}%22%2Ckey%3A%22{{user.apiToken}}%22%7D,&choe=UTF-8&chld=L', alt='qrcode')