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-resource": "1.2.0-rc.2",
"angular-ui": "~0.4.0", "angular-ui": "~0.4.0",
"angular-bootstrap": "~0.5.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", "bootstrap-tour": "0.5.0",
"BrowserQuest": "https://github.com/mozilla/BrowserQuest.git", "BrowserQuest": "https://github.com/mozilla/BrowserQuest.git",
"github-buttons": "git://github.com/mdo/github-buttons.git", "github-buttons": "git://github.com/mdo/github-buttons.git",
@@ -29,11 +29,11 @@
"sticky": "*", "sticky": "*",
"bootstrap-datepicker": "~1.2.0", "bootstrap-datepicker": "~1.2.0",
"bootstrap": "v2.3.2", "bootstrap": "v2.3.2",
"angular-route": "1.2.0-rc.2",
"angular-ui-utils": "~0.0.4", "angular-ui-utils": "~0.0.4",
"angular-sanitize": "1.2.0-rc.2", "angular-sanitize": "1.2.0-rc.2",
"marked": "~0.2.9", "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": { "resolutions": {
"jquery": "~2.0.3", "jquery": "~2.0.3",

View File

@@ -1,21 +1,123 @@
"use strict"; "use strict";
window.habitrpg = angular.module('habitrpg', 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("API_URL", "")
.constant("STORAGE_USER_ID", 'habitrpg-user') .constant("STORAGE_USER_ID", 'habitrpg-user')
.constant("STORAGE_SETTINGS_ID", 'habit-mobile-settings') .constant("STORAGE_SETTINGS_ID", 'habit-mobile-settings')
//.constant("STORAGE_GROUPS_ID", "") // if we decide to take groups offline //.constant("STORAGE_GROUPS_ID", "") // if we decide to take groups offline
.config(['$routeProvider', '$httpProvider', 'STORAGE_SETTINGS_ID', .config(['$stateProvider', '$urlRouterProvider', '$httpProvider', 'STORAGE_SETTINGS_ID',
function($routeProvider, $httpProvider, STORAGE_SETTINGS_ID) { function($stateProvider, $urlRouterProvider, $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'})
.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)); var settings = JSON.parse(localStorage.getItem(STORAGE_SETTINGS_ID));
if (settings && settings.auth) { if (settings && settings.auth) {

View File

@@ -1,13 +1,11 @@
"use strict"; "use strict";
habitrpg.controller("ChallengesCtrl", ['$scope', '$rootScope', 'User', 'Challenges', 'Notification', '$http', 'API_URL', '$compile', habitrpg.controller("ChallengesCtrl", ['$scope', 'User', 'Challenges', 'Notification', '$compile', 'groups', 'challenges',
function($scope, $rootScope, User, Challenges, Notification, $http, API_URL, $compile) { function($scope, User, Challenges, Notification, $compile, groups, challenges) {
$http.get(API_URL + '/api/v1/groups?minimal=true').success(function(groups){ // groups & challenges are loaded as `resolve` via ui-router (see app.js)
$scope.groups = groups; $scope.groups = groups;
}); $scope.challenges = challenges;
$scope.challenges = Challenges.Challenge.query();
//------------------------------------------------------------ //------------------------------------------------------------
// Challenge // Challenge
@@ -92,61 +90,33 @@ habitrpg.controller("ChallengesCtrl", ['$scope', '$rootScope', 'User', 'Challeng
// TODO persist // TODO persist
} }
/** /*
* Render graphs for user scores when the "Challenges" tab is clicked --------------------------
*/ Unsubscribe functions
//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)
$scope.unsubscribe = function(keep) {
/* if (keep == 'cancel') {
-------------------------- $scope.selectedChal = undefined;
Unsubscribe functions } else {
-------------------------- $scope.selectedChal.$leave({keep:keep});
*/
$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.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"; "use strict";
habitrpg.controller("GroupsCtrl", ['$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) { function($scope, $rootScope, Groups, $http, API_URL, $q, User, Members, $location, $state) {
$scope.isMember = function(user, group){ $scope.isMember = function(user, group){
return ~(group.members.indexOf(user._id)); return ~(group.members.indexOf(user._id));
@@ -25,10 +25,10 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Groups', '$http', 'A
$scope.clickMember = function(uid, forceShow) { $scope.clickMember = function(uid, forceShow) {
if (User.user._id == uid && !forceShow) { if (User.user._id == uid && !forceShow) {
if ($location.path() == '/tasks') { if ($state.is('tasks')) {
$location.path('/options'); $state.go('options');
} else { } else {
$location.path('/tasks'); $state.go('tasks');
} }
} else { } else {
// We need the member information up top here, but then we pass it down to the modal controller // 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', .controller("GuildsCtrl", ['$scope', 'Groups', 'User', '$rootScope',
function($scope, Groups, User, $rootScope) { function($scope, Groups, User, $rootScope) {
Groups.fetchGuilds();
$scope.type = 'guild'; $scope.type = 'guild';
$scope.text = 'Guild'; $scope.text = 'Guild';
$scope.newGroup = new Groups.Group({type:'guild', privacy:'private', leader: User.user._id, members: [User.user._id]}); $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', .controller("TavernCtrl", ['$scope', 'Groups', 'User',
function($scope, Groups, User) { function($scope, Groups, User) {
Groups.fetchTavern();
$scope.group = Groups.groups.tavern; $scope.group = Groups.groups.tavern;
$scope.rest = function(){ $scope.rest = function(){

View File

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

View File

@@ -44,9 +44,9 @@ angular.module('groupServices', ['ngResource']).
fetchGuilds: _.once(function(){ fetchGuilds: _.once(function(){
$('#loading-indicator').show(); $('#loading-indicator').show();
Group.query({type:'guilds'}, function(_groups){ Group.query({type:'guilds'}, function(_groups){
$('#loading-indicator').hide();
guildsQ.resolve(_groups); guildsQ.resolve(_groups);
Members.populate(_groups); Members.populate(_groups);
$('#loading-indicator').hide();
}) })
Group.query({type:'public'}, function(_groups){ Group.query({type:'public'}, function(_groups){
publicQ.resolve(_groups); publicQ.resolve(_groups);
@@ -58,8 +58,8 @@ angular.module('groupServices', ['ngResource']).
$('#loading-indicator').show(); $('#loading-indicator').show();
Group.query({type:'tavern'}, function(_groups){ Group.query({type:'tavern'}, function(_groups){
$('#loading-indicator').hide(); $('#loading-indicator').hide();
tavernQ.resolve(_groups[0]);
Members.populate(_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}, timestamp: {type: Date, 'default': Date.now},
members: [{type: String, ref: 'User'}] members: [{type: String, ref: 'User'}]
}, {
minimize: 'false'
}); });
ChallengeSchema.virtual('tasks').get(function () { ChallengeSchema.virtual('tasks').get(function () {

View File

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

View File

@@ -31,6 +31,8 @@ var TaskSchema = new Schema({
broken: String // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, etc broken: String // CHALLENGE_DELETED, TASK_DELETED, UNSUBSCRIBED, etc
// group: {type: 'Strign', ref: 'Group'} // if we restore this, rename `id` above to `challenge` // group: {type: 'Strign', ref: 'Group'} // if we restore this, rename `id` above to `challenge`
} }
}, {
minimize: 'false'
}); });
TaskSchema.methods.toJSON = function() { 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-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/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/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/angular-sanitize/angular-sanitize.min.js')
script(type='text/javascript', src='/bower_components/marked/lib/marked.js') script(type='text/javascript', src='/bower_components/marked/lib/marked.js')
@@ -109,7 +110,7 @@ html
.exp-chart(ng-show='charts.exp') .exp-chart(ng-show='charts.exp')
#main(ng-view) #main(ui-view)
include ./shared/footer 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 include ./filters
div(ng-controller='TasksCtrl') div(ng-controller='TasksCtrl')
habitrpg-tasks(main='true', obj='user') 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') script(type='text/ng-template', id='partials/options.challenges.html')
.span2.well .row-fluid
h4 Filters .span2.well
ul h4 Filters
li(ng-repeat='group in groups') ul
input(type='checkbox', ng-model='search.group') li(ng-repeat='group in groups')
| {{group.name}} input(type='checkbox', ng-model='search.group')
li | {{group.name}}
input(type='checkbox', ng-model='search.members') li
| Subscribed (TODO) input(type='checkbox', ng-model='search.members')
li | Subscribed (TODO)
input(type='checkbox', ng-model='search.members') li
| Available (TODO) input(type='checkbox', ng-model='search.members')
.span10 | Available (TODO)
// Creation form .span10
a.btn.btn-success(ng-click='create()') Create Challenge // Creation form
.create-challenge-from(ng-if='newChallenge') a.btn.btn-success(ng-click='create()') Create Challenge
form(ng-submit='save(newChallenge)') .create-challenge-from(ng-if='newChallenge')
div form(ng-submit='save(newChallenge)')
input.btn.btn-success(type='submit', value='Save') div
input.btn.btn-danger(type='button', ng-click='discard()', value='Discard') input.btn.btn-success(type='submit', value='Save')
select(ng-model='newChallenge.group', ng-required='required', name='Group', ng-options='g._id as g.name for g in groups') input.btn.btn-danger(type='button', ng-click='discard()', value='Discard')
.challenge-options select(ng-model='newChallenge.group', ng-required='required', name='Group', ng-options='g._id as g.name for g in groups')
input.option-content(type='text', ng-model='newChallenge.name', placeholder='Challenge Title', required='required') .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 // Challenges list
.accordion-group(ng-repeat='challenge in challenges | filter:search', ng-init='challenge._locked=true') .accordion-group(ng-repeat='challenge in challenges | filter:search', ng-init='challenge._locked=true')
.accordion-heading .accordion-heading
ul.pull-right.challenge-accordion-header-specs ul.pull-right.challenge-accordion-header-specs
li {{challenge.members.length}} Subscribers li {{challenge.members.length}} Subscribers
li(ng-show='challenge.prize') li(ng-show='challenge.prize')
// prize // prize
table(ng-show='challenge.prize') table(ng-show='challenge.prize')
tr tr
td {{challenge.prize}} td {{challenge.prize}}
td td
span.Pet_Currency_Gem1x span.Pet_Currency_Gem1x
td Prize td Prize
li li
// subscribe / unsubscribe // subscribe / unsubscribe
a.btn.btn-small.btn-danger(ng-show='indexOf(challenge.members, user._id)', ng-click='clickUnsubscribe(challenge, $event)') a.btn.btn-small.btn-danger(ng-show='indexOf(challenge.members, user._id)', ng-click='clickUnsubscribe(challenge, $event)')
i.icon-ban-circle i.icon-ban-circle
| Unsubscribe | Unsubscribe
a.btn.btn-small.btn-success(ng-hide='indexOf(challenge.members, user._id)', ng-click='challenge.$join()') a.btn.btn-small.btn-success(ng-hide='indexOf(challenge.members, user._id)', ng-click='challenge.$join()')
i.icon-ok i.icon-ok
| Subscribe | Subscribe
a.accordion-toggle(data-toggle='collapse', data-target='#accordion-challenge-{{challenge._id}}') {{challenge.name}} (by {{challenge.leader.name}}) 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-body.collapse(id='accordion-challenge-{{challenge._id}}')
.accordion-inner .accordion-inner
// Edit button // Edit button
ul.unstyled() ul.unstyled()
li(ng-show='challenge.leader==user._id && challenge._locked') li(ng-show='challenge.leader==user._id && challenge._locked')
button.btn.btn-default(ng-click='challenge._locked = false') Edit button.btn.btn-default(ng-click='challenge._locked = false') Edit
li(ng-hide='challenge._locked') li(ng-hide='challenge._locked')
button.btn.btn-primary(ng-click='save(challenge)') Save button.btn.btn-primary(ng-click='save(challenge)') Save
button.btn.btn-danger(ng-click='delete(challenge)') Delete button.btn.btn-danger(ng-click='delete(challenge)') Delete
button.btn.btn-default(ng-click='challenge._locked=true') Cancel button.btn.btn-default(ng-click='challenge._locked=true') Cancel
div(ng-hide='challenge._locked') div(ng-hide='challenge._locked')
.-options .-options
input.option-content(type='text', ng-model='challenge.name') input.option-content(type='text', ng-model='challenge.name')
textarea.option-content(cols='3', placeholder='Description', ng-model='challenge.description') textarea.option-content(cols='3', placeholder='Description', ng-model='challenge.description')
// <input type=number class='option-content' placeholder='Gems Prize' value={@challenge.prize} /> // <input type=number class='option-content' placeholder='Gems Prize' value={@challenge.prize} />
hr hr
div(ng-if='challenge.description') {{challenge.description}} div(ng-if='challenge.description') {{challenge.description}}
habitrpg-tasks(obj='challenge', main=false) habitrpg-tasks(obj='challenge', main=false)
h3 Statistics h3 Statistics
div(ng-repeat='member in challenge.members', ng-init='member._locked = true') div(ng-repeat='member in challenge.members', ng-init='member._locked = true')
h4 {{member.profile.name}} h4 {{member.profile.name}}
habitrpg-tasks(main=false, obj='member') 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 // 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 // Subscribe to that ticket & change this when they fix
ul.nav.nav-tabs script(type='text/ng-template', id='partials/options.groups.tavern.html')
li.active include ./tavern
a(data-target='#groups-party', data-toggle='tab') Party
li
a(data-target='#groups-guilds', data-toggle='tab', ng-click='fetchGuilds()') Guilds
.tab-content(ng-controller='PartyCtrl') script(type='text/ng-template', id='partials/options.groups.party.html')
#groups-party.tab-pane.active div(ng-show='group._id')
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 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') .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(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 script(type='text/ng-template', id='partials/options.groups.html')
include ./create-group 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 .span4
.tavern-pane .tavern-pane
table 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 .grid
.module.full-width .module.full-width
span.option-box.pull-right.wallet span.option-box.pull-right.wallet
include ../shared/gems include ../shared/gems
ul.nav.nav-tabs ul.nav.nav-tabs
li.active li(ng-class="{ active: $state.includes('options.profile') }")
a(data-toggle='tab', data-target='#profile-tab') a(ui-sref='options.profile')
i.icon-user i.icon-user
| Profile | Profile
li li(ng-class="{ active: $state.includes('options.groups') }")
a(data-toggle='tab',data-target='#groups-tab', ng-click='fetchParty()') a(ui-sref='options.groups')
i.icon-heart i.icon-heart
| Groups | Groups
li(ng-show='user.flags.dropsEnabled') li(ng-class="{ active: $state.includes('options.inventory') }", ng-if='user.flags.dropsEnabled')
a(data-toggle='tab',data-target='#inventory-tab') a(ui-sref='options.inventory')
i.icon-gift i.icon-gift
| Inventory | Inventory
li(ng-show='user.flags.dropsEnabled') li(ng-class="{ active: $state.includes('options.challenges') }")
a(data-toggle='tab',data-target='#stable-tab') a(ui-sref='options.challenges')
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')
i.icon-bullhorn i.icon-bullhorn
| Challenges | Challenges
li li(ng-class="{ active: $state.includes('options.settings') }")
a(data-toggle='tab',data-target='#settings-tab') a(ui-sref='options.settings')
i.icon-wrench i.icon-wrench
| Settings | Settings
.tab-content .tab-content
.tab-pane.active#profile-tab .tab-pane.active
include ./profile div(ui-view)
.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

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') script(id='partials/options.profile.avatar.html', type='text/ng-template')
.row-fluid
// ---- Customize ----- .span4.border-right
.span4.border-right menu(type='list')
menu(type='list') // body-type
// 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')
li.customize-menu li.customize-menu
menu(label='Clothing') menu(label='Head')
button.f_armor_0_v1.customize-option(type='button', ng-click='set("preferences.armorSet","v1")') menu
button.f_armor_0_v2.customize-option(type='button', ng-click='set("preferences.armorSet","v2")') 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 ------ menu(ng-show='user.preferences.gender=="f"', type='list')
.span4.border-right li.customize-menu
include ../shared/profiles/stats 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.border-right
.span4 // hair
button.btn.btn-default(ng-click='_editing.profile = true', ng-show='!_editing.profile') Edit li.customize-menu
button.btn.btn-primary(ng-click='save()', ng-show='_editing.profile') Save menu(label='Hair')
div(ng-show='!_editing.profile') button(class='{{user.preferences.gender}}_hair_blond customize-option', type='button', ng-click='set("preferences.hair","blond")')
h4 Display Name button(class='{{user.preferences.gender}}_hair_black customize-option', type='button', ng-click='set("preferences.hair","black")')
span(ng-show='profile.profile.name') {{profile.profile.name}} button(class='{{user.preferences.gender}}_hair_brown customize-option', type='button', ng-click='set("preferences.hair","brown")')
span.muted(ng-hide='profile.profile.name') - None - 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 .span4.border-right
img(ng-show='profile.profile.imageUrl', ng-src='{{profile.profile.imageUrl}}') // skin
span.muted(ng-hide='profile.profile.imageUrl') - None - 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 // Rainbow Skin
markdown(ng-show='profile.profile.blurb', ng-model='profile.profile.blurb') h5.
span.muted(ng-hide='profile.profile.blurb') - None - Rainbow Skins - 2<span class="Pet_Currency_Gem1x inline-gems"/>/skin
//{{profile.profile.blurb | linky:'_blank'}} //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 // Special Events
ul(ng-show='profile.profile.websites.length > 0') div.well.limited-edition
// TODO let's remove links eventually, since we can do markdown on profiles .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')
li(ng-repeat='website in profile.profile.websites') | Limited Edition&nbsp;
a(target='_blank', ng-href='{{website}}') {{website}} i.icon.icon-question-sign
span.muted(ng-hide='profile.profile.websites.length > 0') - None - 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') script(id='partials/options.profile.stats.html', type='text/ng-template')
// TODO use photo-upload instead: https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/xMmADvxBOak .row-fluid
.control-group.option-large .span6.border-right
label.control-label Display Name include ../shared/profiles/stats
input.option-content(type='text', placeholder='Full Name', ng-model='editingProfile.name') .span6.border-right
.control-group.option-large include ../shared/profiles/achievements
label.control-label Photo Url
input.option-content(type='url', ng-model='editingProfile.imageUrl', placeholder='Image Url') script(id='partials/options.profile.profile.html', type='text/ng-template')
.control-group.option-large button.btn.btn-default(ng-click='_editing.profile = true', ng-show='!_editing.profile') Edit
label.control-label Blurb button.btn.btn-primary(ng-click='save()', ng-show='_editing.profile') Save
textarea.option-content(style='height:15em;', placeholder='Blurb', ng-model='editingProfile.blurb') div(ng-show='!_editing.profile')
include ../shared/formatting-help h4 Display Name
.control-group.option-large span(ng-show='profile.profile.name') {{profile.profile.name}}
label.control-label Websites span.muted(ng-hide='profile.profile.name') - None -
form(ng-submit='addWebsite()')
input.option-content(type='url', ng-model='_newWebsite', placeholder='Add Website') h4 Photo
ul img(ng-show='profile.profile.imageUrl', ng-src='{{profile.profile.imageUrl}}')
// would prefer if there were and index in #each, instead using data-website to search with indexOf span.muted(ng-hide='profile.profile.imageUrl') - None -
li(ng-repeat='website in editingProfile.websites')
| {{website}} h4 Blurb
a(ng-click='removeWebsite($index)') markdown(ng-show='profile.profile.blurb', ng-model='profile.profile.blurb')
i.icon-remove 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') script(type='text/ng-template', id='partials/options.settings.html')
.personal-options.span6.border-right .row-fluid
h2 Settings .personal-options.span6.border-right
h4 Custom Day Start h2 Settings
.option-group.option-short h4 Custom Day Start
input.option-content.option-time(type='number', min='0', max='24', ng-model='user.preferences.dayStart', ng-change='saveDayStart()') .option-group.option-short
span.input-suffix :00 (24h clock) input.option-content.option-time(type='number', min='0', max='24', ng-model='user.preferences.dayStart', ng-change='saveDayStart()')
div span.input-suffix :00 (24h clock)
small div
| 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). small
hr | 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).
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')
hr hr
h4 Change Password h4 Misc
form(ng-submit='changePassword(changePass)', ng-show='user.auth.local') button.btn(ng-hide='user.preferences.hideHeader', ng-click='set("preferences.hideHeader",true)') Hide Header
.control-group button.btn(ng-show='user.preferences.hideHeader', ng-click='set("preferences.hideHeader",false)') Show Header
input(type='password', placeholder='Old Password', ng-model='changePass.oldPassword', required) button.btn(ng-click='showTour()') Show Tour
.control-group button.btn(ng-click='showBailey()') Show Bailey
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 div(ng-show='user.auth.local')
h4 Danger Zone hr
a.btn.btn-danger(ng-click='modals.reset = true', tooltip='Resets your entire account (dangerous).') Reset h4 Change Password
a.btn.btn-danger(ng-click='modals.restore = true', tooltip='Restores attributes to your character.') Restore form(ng-submit='changePassword(changePass)', ng-show='user.auth.local')
a.btn.btn-danger(ng-click='modals.delete = true', tooltip='Delete your account.') Delete .control-group
.span6 input(type='password', placeholder='Old Password', ng-model='changePass.oldPassword', required)
h2 API .control-group
small Copy these for use in third party applications. input(type='password', placeholder='New Password', ng-model='changePass.newPassword', required)
h6 User ID .control-group
pre.prettyprint {{user.id}} input(type='password', placeholder='Confirm New Password', ng-model='changePass.confirmNewPassword', required)
h6 API Token input.btn(type='submit', value='Submit')
pre.prettyprint {{user.apiToken}}
h6 QR Code hr
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') 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')