rewrite: merge in some more litenull stuff & delete the superfluous files

This commit is contained in:
Tyler Renelle 2013-08-28 13:38:04 -04:00
parent aafb9b6cdd
commit 1b22928c0a
49 changed files with 131 additions and 44284 deletions

View file

@ -1,3 +0,0 @@
{
"directory": "app/bower_components"
}

View file

@ -1,22 +0,0 @@
HabitRPG Rewrite
===============
HabitRPG Rewrite under development. Built using Angular.
**Note: This branch is under development, and these instructions may fall out of date. They were accurate as of August 5, 2013.** Should you encounter this, join #habitrpg on IRC (Freenode) and talk to litenull.
The general steps are:
1. Set up and run the [server](https://github.com/lefnire/habitrpg/wiki/Running-Locally-%28Server%29)
1. Clone the repo
1. Install all dependencies
1. Run the client
Or, expressed in commands on the command line:
1. `git clone --branch angular_rewrite git://github.com/lefnire/habitrpg habitrpg-angular`
1. `npm install`
1. `bower install` (if you don't have `bower`, do `npm install -g bower` — might need `sudo`)
1. `node server.js`
To access the site, open http://localhost:3003 in your browser.

View file

@ -1,132 +0,0 @@
<!doctype html>
<html lang="en" ng-app="habitrpg" ng-controller="RootCtrl">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<title>HabitRPG</title>
<link href='//fonts.googleapis.com/css?family=Lato:300,300italic' rel='stylesheet' type='text/css'>
<style>
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none;
}
</style>
</head>
<body ng-cloak>
<div ng-controller="WrapperCtrl">
<div id="undefined-sticky-wrapper" class="sticky-wrapper">
<div class="header-wrap">
<div class="user-menu">
<ul class="nav site-nav">
<li class="flyout">
<h1 class="task-action-btn tile solid user-reporter">
<div ng-show="user.auth.local.username">{{user.auth.local.username}}</div>
</h1>
<ul class="flyout-content nav stacked">
<li>
<a class="task-action-btn tile solid" ng-click="showMenu()">Options</a>
</li>
<li>
<a class="task-action-btn tile solid" href="" ng-click="logout()">Logout</a>
</li>
</ul>
</li>
</ul>
</div>
<div ng-controller="CharacterCtrl">
<header class="site-header" role="banner">
<div class="herobox-wrap main-herobox" ng-click="showMenu()">
<figure class="herobox"
data-name="{{user.auth.local.username}}"
data-level="{{user.stats.lvl}}"
data-checkuser="isUser"
>
<div class='character-sprites'>
<span class='{{user.preferences.gender}}_skin_{{user.preferences.skin}}'></span>
<span class='{{user.preferences.gender}}_hair_{{user.preferences.hair}}'></span>
<span class="{{user.preferences.gender}}_armor_{{user.items.armor}}"></span>
<span class="{{equipped(user, 'head')}}"></span>
<span class="{{user.preferences.gender}}_head_0"></span>
<span class='{{user.preferences.gender}}_shield_{{user.items.shield}}'></span>
<span class='{{user.preferences.gender}}_weapon_{{user.items.weapon}}'></span>
</div>
</figure>
</div>
<div class="hero-stats">
<div class="meter health" Title="Health">
<div class="bar" style="width:{{hpPercent(user.stats.hp)}}%"></div>
</div>
<div class="meter experience" Title="Experience">
<div class="bar" style="width:{{expPercent(user.stats.exp, user.stats.lvl)}}%"></div>
</div>
</div>
</header>
</div>
</div>
</div>
</div>
<br>
<div ng-view></div>
<!-- Exclude these from the build process, minify borks angular dep-inj var names like $scope -->
<!-- See http://docs.angularjs.org/guide/di "$injection Annotation" for when we're ready to deploy -->
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
<script src="bower_components/angular-cookies/angular-cookies.js"></script>
<script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
<!-- build:js scripts/scripts.js -->
<!-- Vendor -->
<script src="bower_components/underscore/underscore-min.js"></script>
<script src="bower_components/moment/moment.js"></script>
<script src="scripts/vendor/cdv-plugin-fb-connect.js"></script>
<script src="scripts/vendor/facebook-js-sdk.js"></script>
<script src="bower_components/jquery/jquery.min.js"></script>
<script src="scripts/vendor/jquery-ui-1.10.3.custom.js"></script>
<!-- touch events (bower: hammerjs and monospaced/angular-hammer) -->
<script src="bower_components/hammerjs/dist/hammer.min.js"></script>
<script src="bower_components/hammerjs/dist/jquery.hammer.min.js"></script>
<script src="bower_components/angular-hammer/angular-hammer.js"></script>
<!-- HabitRPG Shared -->
<script src="bower_components/habitrpg-shared/browser/browser.debug.js"></script>
<script src="scripts/vendor/jquery.transit.min.js"></script>
<!-- App -->
<script src="scripts/app.js"></script>
<script src="scripts/controllers/rootCtrl.js"></script>
<script src="scripts/controllers/settingsCtrl.js"></script>
<script src="scripts/filters/filters.js"></script>
<script src="scripts/controllers/tasksCtrl.js"></script>
<script src="scripts/controllers/taskDetailsCtrl.js"></script>
<script src="scripts/directives/taskFocus.js"></script>
<script src="scripts/directives/taskBlur.js"></script>
<script src="scripts/controllers/navCtrl.js"></script>
<script src="scripts/controllers/wrapperCtrl.js"></script>
<script src="scripts/controllers/statsCtrl.js"></script>
<script src="scripts/controllers/characterCtrl.js"></script>
<script src="scripts/controllers/menuCtrl.js"></script>
<script src="scripts/controllers/authCtrl.js"></script>
<script src="scripts/services/userServices.js"></script>
<script src="scripts/services/sharedServices.js"></script>
<script src="scripts/services/authServices.js"></script>
<script src="scripts/services/notificationServices.js"></script>
<script src="scripts/controllers/notificationCtrl.js"></script>
<script src="scripts/controllers/loginCtrl.js"></script>
<script src="scripts/controllers/eventCtrl.js"></script>
<script src="scripts/controllers/userAvatarCtrl.js"></script>
<!-- endbuild -->
</body>
</html>

View file

@ -1,74 +0,0 @@
'use strict';
/**
* The main HabitRPG app module.
*
* @type {angular.Module}
*/
var habitrpg = angular.module('habitrpg', ['userServices', 'sharedServices', 'authServices', 'notificationServices', 'hmTouchEvents'])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/home', {templateUrl: 'views/home.html'})
.when('/login', {templateUrl: 'views/login.html'})
.when('/settings', {templateUrl: 'views/settings.html'})
.when('/profile', {templateUrl: 'views/profile.html'})
.when('/options', {templateUrl: 'views/options.html'})
.when('/:action', {templateUrl: 'views/list.html'})
.when('/tasks/:taskId', {templateUrl: 'views/details.html'})
.when('/todo/active', {templateUrl: 'views/list.html'})
.when('/todo/completed', {templateUrl: 'views/list.html'})
.otherwise({redirectTo: '/habit'});
}])
.config(['$compileProvider', function ($compileProvider) {
$compileProvider.urlSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|tel):/);
}]);
// Touch directive, binding to touchstart as to not wait for 300ms
habitrpg.directive('gfTap', ["$location", "$parse", function ($location, $parse) {
return function (scope, element, attrs) {
var tapping = false;
element.bind('touchstart', function () {
tapping = true;
});
element.bind('touchmove', function () {
tapping = false
});
element.bind('touchend', function (event) {
if (tapping) {
var fn = $parse(attrs['gfTap']);
if (attrs['href']) {
var location = attrs['href'].replace('#', '/');
$location.path(location);
}
scope.$apply(function () {
fn(scope, {$event: event})
});
}
});
};
}]);
habitrpg.directive('sort', function (User) {
return function ($scope, element, attrs, ngModel) {
$(element).sortable({
axis: "y",
start: function (event, ui) {
ui.item.data('startIndex', ui.item.index());
},
stop: function (event, ui) {
var taskType = angular.element(ui.item[0]).scope().task.type + 's'
var startIndex = ui.item.data('startIndex');
var task = User.user[taskType][startIndex];
User.log({op: 'sortTask', task: task, from: startIndex, to: ui.item.index()});
}
});
}
});

View file

@ -1,27 +0,0 @@
'use strict';
/**
* The authentication controller (login & facebook)
*
*/
habitrpg.controller('AuthCtrl', function AuthCtrl($scope, Facebook, LocalAuth, User, $http, $location) {
$scope.Facebook = Facebook;
$scope.Local = LocalAuth;
$scope.uuid = ''
$scope.apiToken = ''
$scope.apiLogin = function() {
User.authenticate($scope.uuid, $scope.apiToken, function(err) {
if (!err) {
alert('Login succesfull!');
$location.path("/habit");
User.fetch()
}
});
}
});

View file

@ -1,32 +0,0 @@
'use strict';
/**
* The character controller:
*
*/
habitrpg.controller( 'CharacterCtrl', function CharacterCtrl( $scope, $location, filterFilter, User ) {
$scope.user = User.user;
$scope.equipped = function(user, type) {
return window.habitrpgShared.helpers.equipped(user, type);
}
$scope.$watch('user.tasks', function(){
$scope.hpPercent = function(hp) {
return (hp / 50) * 100;
}
$scope.expPercent = function(exp, level) {
return Math.round((exp / window.habitrpgShared.algos.tnl(level)) * 100);
}
})
$scope.showUserAvatar = function() {
$('.userAvatar').show()
}
});

View file

@ -1,14 +0,0 @@
'use strict';
/**
* Phonegap events
*
*/
if (typeof cordova != 'undefined') {
// the second parameter is the callback to be called
document.addEventListener("online", yourCallbackFunction, false);
document.addEventListener("offline", yourCallbackFunction, false);
document.addEventListener("resume", yourCallbackFunction, false);
document.addEventListener("pause", yourCallbackFunction, false);
}

View file

@ -1,11 +0,0 @@
'use strict';
/**
* The login controller:
*
*/
habitrpg.controller( 'LoginCtrl', function CharacterCtrl( $scope, $location, filterFilter, User ) {
});

View file

@ -1,43 +0,0 @@
'use strict';
/**
* The menu controller:
* - sets the menu options, should we do it dynamic so it generates the menu like: width = 1/elements * 100 ?
* - exposes the model to the template and provides event handlers
*/
habitrpg.controller( 'MenuCtrl', function MenuCtrl( $scope, $location, filterFilter) {
var nav = $scope.nav = [
{
'name' :'#habit',
'img' :'explorer.png',
'link' :'Habits'
},
{
'name' :'#daily',
'img' :'contacts.png',
'link' :'Dailies'
},
{
'name' :'#todo',
'img' :'todo.png',
'link' :'Todos'
},
{
'name' :'#reward',
'img' :'explorer.png',
'link' :'Rewards'
}
]
});

View file

@ -1,34 +0,0 @@
'use strict';
/**
* The nav controller:
* - sets the menu options, should we do it dynamic so it generates the menu like: width = 1/elements * 100 ?
* - exposes the model to the template and provides event handlers
*/
habitrpg.controller( 'NavCtrl', function NavCtrl( $scope, $location, filterFilter ) {
var nav = $scope.nav = [
{
'name' :'#habit',
'img' :'explorer.png'
},
{
'name' :'#daily',
'img' :'contacts.png'
},
{
'name' :'#todo',
'img' :'todo.png'
},
{
'name' :'#reward',
'img' :'explorer.png'
}
]
});

View file

@ -1,13 +0,0 @@
'use strict';
habitrpg.controller('NotificationCtrl', function ($scope, $location, filterFilter, Notification) {
$scope.data = Notification.get();
$('#notification').bind('touchend.swipe', function (event) {
Notification.clearTimer();
Notification.hide();
});
});

View file

@ -1,8 +0,0 @@
'use strict';
// Make user and settings available for everyone through root scope.
habitrpg.controller( 'RootCtrl', function ( $scope, $rootScope, User) {
$rootScope.User = User;
$rootScope.user = User.user;
$rootScope.settings = User.settings;
});

View file

@ -1,17 +0,0 @@
'use strict';
// Make user and settings available for everyone through root scope.
habitrpg.controller('SettingsCtrl', function ($scope, User, $location) {
$scope.resetApp = function () {
localStorage.clear();
location.reload();
};
$scope.auth = function (id, token) {
User.authenticate(id, token, function (err) {
if (!err) {
alert('Login succesfull!');
$location.path("/habit");
}
});
}
});

View file

@ -1,50 +0,0 @@
'use strict';
habitrpg.controller('TaskDetailsCtrl', function TaskDetailsCtrl($scope, $rootScope, $location, User) {
$scope.task = $rootScope.selectedTask;
$scope.editing = false;
$scope.editedTask = null;
$scope.goBack = function () {
$rootScope.selectedTask = null;
$location.path('/' + $scope.task.type);
};
$scope.edit = function () {
$scope.originalTask = _.clone($scope.task); // TODO deep clone?;
$scope.editedTask = $scope.task;
$scope.editing = true;
};
$scope.save = function () {
var task = $scope.task;
User.log([
{op: 'set', path: "tasks." + task.id + ".text", value: task.text},
{op: 'set', path: "tasks." + task.id + ".notes", value: task.notes}
]);
$rootScope.selectedTask = null;
$location.path('/' + $scope.task.type);
$scope.editing = false;
};
$scope.cancel = function () {
// reset $scope.task to $scope.originalTask
for (var key in $scope.task) {
$scope.task[key] = $scope.originalTask[key];
}
$scope.originalTask = null;
$scope.editedTask = null;
$scope.editing = false;
};
$scope.delete = function () {
var task = $scope.task;
var tasks = User.user[task.type+'s'];
User.log({op: 'delTask', task: task});
$scope.goBack();
delete tasks.splice(tasks.indexOf(task),1);
};
});

View file

@ -1,305 +0,0 @@
'use strict';
habitrpg.controller('TasksCtrl', function TasksCtrl($scope, $rootScope, $location, filterFilter, User, Algos, Helpers, Notification) {
$scope.user = User.user;
$scope.$watch('User.user.stats.gp', function() {
$scope.money_gold = Math.round(User.user.stats.gp)
})
$scope.taskTypeTitle = function () {
// show title according to the location
switch ($location.path().split('/')[1]) {
case 'habit':
return 'Habits';
case 'daily':
return 'Dailies';
case 'todo':
return 'Todos';
case 'reward':
return 'Rewards';
default :
return "";
}
};
$scope.taskTypeTitleSingular = function () {
// show title according to the location, singular form
return $scope.taskTypeTitle().slice(0,-1);
};
$scope.taskType = function () {
return $location.path().split('/')[1]
};
$scope.tasks = function () {
//return task array based on our location i.e. /habit will return user.habits[]
var tasks = []
//return User.user[$scope.taskType() + 's']
_.each(User.user['habits'], function(el, index) {
tasks.push(el)
})
_.each(User.user['dailys'], function(el, index) {
tasks.push(el)
})
_.each(User.user['todos'], function(el, index) {
tasks.push(el)
})
_.each(User.user['rewards'], function(el, index) {
tasks.push(el)
})
return tasks
};
$scope.taskFilter = function (task) {
return ($location.path() == '/todo') ? !task.completed :
($location.path() == '/todo/completed') ? task.completed :
true;
};
$scope.score = function (task, direction) {
//save current stats to compute the difference after scoring.
var statsDiff = {};
var oldStats = _.clone(User.user.stats);
Algos.score(User.user, task, direction);
//compute the stats change.
_.each(oldStats, function (value, key) {
var newValue = User.user.stats[key];
if (newValue !== value) {
statsDiff[key] = newValue - value;
}
});
//notify user if there are changes in stats.
if (Object.keys(statsDiff).length > 0) {
// Notification.push({type: 'stats', stats: statsDiff});
}
User.log({op: 'score', task: task, dir: direction});
};
$scope.getClass = function(task) {
var out = ''
if (task.type == 'daily' && task.completed)
out += ' completed'
else if (task.value < -20)
out += ' color-worst'
else if (task.value < -10)
out += ' color-worse'
else if (task.value < -1)
out += ' color-bad'
else if (task.value < 1)
out += ' color-neutral'
else if (task.value < 5)
out += ' color-good'
else if (task.value < 10)
out += ' color-better'
else
out += ' color-best'
return out
}
$scope.addTask = function (type) {
var task = null
if (type == 'habit') {
task = $scope.newTaskHabit
}else if (type == 'daily') {
task = $scope.newTaskDailies
}else if (type == 'todo') {
task = $scope.newTaskTodo
}else if (type == 'reward') {
task = $scope.newTaskReward
}
if (!task.length) {
return;
}
var defaults = {
text: task,
type: type,
value: type == 'reward' ? 20 : 0
},
extra = {};
switch (type) {
case 'habit':
extra = {up: true, down: true};
break;
case 'daily':
case 'todo':
extra = {completed: false};
break;
}
var newTask = _.defaults(extra, defaults);
newTask.id = Helpers.uuid();
User.user[newTask.type + 's'].unshift(newTask)
$scope.newTask = '';
User.log({op: 'addTask', task: newTask});
//Add the new task to the actions log
};
$scope.delTask = function(taskObj) {
User.log({op:'delTask', task:taskObj})
}
$scope.clearDoneTodos = function () {
//We can't alter $scope.user.tasks here. We have to invoke API call.
//To be implemented
};
$scope.selectTask = function (task) {
$rootScope.selectedTask = task;
$location.path('/tasks/' + task.id)
}
$scope.changeCheck = function (task) {
// This is calculated post-change, so task.completed=true if they just checked it
if (task.completed) {
$scope.score(task, 'up')
} else {
$scope.score(task, 'down')
}
}
$scope.editTask = function(task) {
if (!task.editing) {
task.editing = true
if (typeof task.tags == 'undefined') {
task.tags = {}
}
}else{
task.editing = false
}
}
$scope.save = function(task) {
var ops = ([
{op: 'set', path: "tasks." + task.id + ".text", value: task.text},
{op: 'set', path: "tasks." + task.id + ".notes", value: task.notes},
{op: 'set', path: "tasks." + task.id + ".up", value: task.up},
{op: 'set', path: "tasks." + task.id + ".down", value: task.down},
{op: 'set', path: "tasks." + task.id + ".priority", value: task.priority},
{op: 'set', path: "tasks." + task.id + ".date", value: task.date},
{op: 'set', path: "tasks." + task.id + ".price", value: task.price},
])
_.each(task.tags, function(el, key, list) {
ops.push({op: 'set', path: "tasks." + task.id + ".tags." + key, value: el})
})
_.each(task.repeat, function(el, key, list) {
ops.push({op: 'set', path: "tasks." + task.id + ".repeat." + key, value: el})
})
User.log(ops)
task.editing = false
}
$scope.showAdvancedOptions = function(task) {
if (!task.advanced) {
task.advanced = true
}else{
task.advanced = false
}
}
$scope.setPriority = function(task, priority) {
task.priority = priority
}
$scope.getPriority = function(task, priority) {
if (task.priority == priority) {
return true;
}else{
return false;
}
}
$scope.getRepeat = function(task, repeat) {
var enabled = '';
_.each(task.repeat, function(el, key, list) {
if (key == repeat && el == true) {
enabled = true
}
})
if (enabled) {
return true
}else{
return false
}
}
$scope.setRepeat = function(task, repeat) {
if (typeof task.repeat == 'undefined') {
var obj = {}
obj[repeat] = true;
task.repeat = {}
task.repeat = obj
return true
}
if (!task.repeat[repeat]) {
task.repeat[repeat] = true
}else{
task.repeat[repeat] = false
}
}
$scope.addTag = function(task, tag) {
var obj = {}
obj[tag] = true
task.tags.push(obj)
}
$scope.toggleTag = function(task, tag) {
var obj = {}
if (typeof task.tags != 'undefined') {
if (!task.tags[tag]) {
task.tags[tag] = false;
}else{
task.tags[tag] = true
}
}else{
task.tags = {}
task.tags[tag] = true
}
}
$scope.deleteTask = function(task) {
var info = confirm('Are you sure you want to delete this task ?')
if (info == true) {
_.each(User.user[task.type + 's'], function(el, index) {
if (el.id == task.id) {
User.user[task.type + 's'].splice(index, 1)
}
})
User.log({op:'delTask', task:task})
}
}
});

View file

@ -1,38 +0,0 @@
'use strict';
/**
* The character controller:
*
*/
habitrpg.controller( 'userAvatarCtrl', function CharacterCtrl( $scope, $location, filterFilter, User ) {
$scope.user = User.user;
$scope.changeHair = function(color) {
User.user.preferences.hair = color;
User.log({op:"set",path:"preferences.hair",value:color})
}
$scope.changeSkin = function(color) {
User.user.preferences.skin = color
User.log({op:"set",path:"preferences.skin",value:color})
}
$scope.changeSex = function(gender) {
User.user.preferences.gender = gender
User.log({op:"set",path:"preferences.gender",value:gender})
}
$scope.changeArmor = function(set) {
User.user.preferences.armorSet = v
User.log({op:"set",path:"preferences.armorSet",value:set})
}
$scope.hideUserAvatar = function() {
$('.userAvatar').hide()
}
});

View file

@ -1,28 +0,0 @@
'use strict';
/**
* The nav controller:
* - sets the menu options, should we do it dynamic so it generates the menu like: width = 1/elements * 100 ?
* - exposes the model to the template and provides event handlers
*/
habitrpg.controller( 'WrapperCtrl', function WrapperCtrl( $scope, $location, filterFilter, Facebook ) {
$scope.showMenu = function() {
if ($location.path() == '/options') {
$location.path('/')
}else{
$location.path('/options')
}
}
$scope.logout = function() {
localStorage.clear()
$location.path('login')
location.reload()
}
});

View file

@ -1,12 +0,0 @@
'use strict';
/**
* Directive that executes an expression when the element it is applied to loses focus.
*/
habitrpg.directive('taskBlur', function() {
return function( scope, elem, attrs ) {
elem.bind('blur', function() {
scope.$apply(attrs.taskBlur);
});
};
});

View file

@ -1,16 +0,0 @@
'use strict';
/**
* Directive that places focus on the element it is applied to when the expression it binds to evaluates to true.
*/
habitrpg.directive('taskFocus', function( $timeout ) {
return function( scope, elem, attrs ) {
scope.$watch(attrs.taskFocus, function( newval ) {
if ( newval ) {
$timeout(function() {
elem[0].focus();
}, 0, false);
}
});
};
});

View file

@ -1,10 +0,0 @@
angular.module('habitrpg')
.filter('gold', function () {
return function (gp) {
return Math.floor(gp);
}
}).filter('silver', function () {
return function (gp) {
return Math.floor((gp - Math.floor(gp))*100);
}
});

View file

@ -1,98 +0,0 @@
'use strict';
/**
* Services that persists and retrieves user from localStorage.
*/
var facebook = {}
angular.module('authServices', ['userServices']).
factory('Facebook', function($http, User) {
//TODO FB.init({appId: '${section.parameters['facebook.app.id']}', status: true, cookie: true, xfbml: true});
var auth, user = User.user;
facebook.handleStatusChange = function(session) {
if (session.authResponse) {
FB.api('/me', {
fields: 'name, picture, email'
}, function(response) {
console.log(response.error)
if (!response.error) {
var data = {
name: response.name,
facebook_id: response.id,
email: response.email
}
$http.post('http://127.0.0.1:3000/api/v1/user/auth/facebook', data).success(function(data, status, headers, config) {
User.authenticate(data.id, data.token, function(err) {
if (!err) {
alert('Login succesfull!');
$location.path("/habit");
}
});
}).error(function(response) {
console.log('error')
})
} else {
alert('napaka')
}
//clearAction();
});
} else {
document.body.className = 'not_connected';
//clearAction();
}
}
return {
authUser: function() {
FB.Event.subscribe('auth.statusChange', facebook.handleStatusChange);
},
getAuth: function() {
return auth;
},
login: function() {
FB.login(null, {
scope: 'email'
});
},
logout: function() {
FB.logout(function(response) {
window.location.reload();
});
}
}
})
.factory('LocalAuth', function($http, User) {
var auth, user = User.user;
return {
getAuth: function() {
return auth;
},
login: function() {
user.id = '';
user.apiToken = '';
User.authenticate();
return;
},
logout: function() {}
}
});

View file

@ -1,16 +0,0 @@
'use strict';
/**
* Services that persists and retrieves user from localStorage.
*/
angular.module('sharedServices', [] ).
factory("Items", function($rootScope){
return window.habitrpgShared.items;
}).
factory("Algos", function($rootScope){
return window.habitrpgShared.algos;
}).
factory("Helpers", function($rootScope){
return window.habitrpgShared.helpers;
});

View file

@ -1,212 +0,0 @@
'use strict';
/**
* Services that persists and retrieves user from localStorage.
*/
angular.module('userServices', []).
factory('User', function($http, $location, $rootScope, $timeout) {
var STORAGE_ID = 'habitrpg-user',
HABIT_MOBILE_SETTINGS = 'habit-mobile-settings',
authenticated = false,
defaultSettings = {
auth: {
apiId: '',
apiToken: ''
},
sync: {
queue: [],
//here OT will be queued up, this is NOT call-back queue!
sent: [] //here will be OT which have been sent, but we have not got reply from server yet.
},
fetching: false,
// whether fetch() was called or no. this is to avoid race conditions
online: false
},
settings = {},
//habit mobile settings (like auth etc.) to be stored here
URL = 'https://beta.habitrpg.com/api/v1/user/batch-update',
schema = {
stats: {
gp: 0,
exp: 0,
lvl: 1,
hp: 50
},
party: {
current: null,
invitation: null
},
items: {
weapon: 0,
armor: 0,
head: 0,
shield: 0,
pets: [],
eggs: []
},
preferences: {
gender: 'm',
skin: 'white',
hair: 'blond',
armorSet: 'v1'
},
auth: {
timestamps: {
savedAt: +new Date
}
},
tasks: [],
habits:[],
dailys:[],
rewards:[],
todos:[],
// note task-types are differentiated / filtered by type {habit, daily, todo, reward}
lastCron: 'new',
balance: 1,
flags: {}
},
user = {}; // this is stored as a reference accessible to all controllers, that way updates propagate
var syncQueue = function(cb) {
if (!authenticated) {
alert("Not authenticated, can't sync, go to settings first.");
return;
}
var queue = settings.sync.queue;
var sent = settings.sync.sent;
if (queue.length === 0) {
console.log('Sync: Queue is empty');
return;
}
if (settings.fetching) {
console.log('Sync: Already fetching');
return;
}
if (settings.online !== true) {
console.log('Sync: Not online');
return;
}
settings.fetching = true;
// move all actions from queue array to sent array
_.times(queue.length, function() {
sent.push(queue.shift());
});
$http.post(URL, sent).success(function(data, status, heacreatingders, config) {
data.tasks = _.toArray(data.tasks);
//make sure there are no pending actions to sync. If there are any it is not safe to apply model from server as we may overwrite user data.
sent.length = 0;
settings.fetching = false;
save();
if (cb) {
cb(false)
}
syncQueue(); // call syncQueue to check if anyone pushed more actions to the queue while we were talking to server.
}).error(function(data, status, headers, config) {
//move sent actions back to queue
_.times(sent.length, function() {
queue.push(sent.shift())
});
settings.fetching = false;
});
};
var fetch = function() {
$http.post(URL, {})
.success(function(response) {
_.extend(user,response)
})
}
var save = function() {
localStorage.setItem(STORAGE_ID, JSON.stringify(user));
localStorage.setItem(HABIT_MOBILE_SETTINGS, JSON.stringify(settings));
};
var userServices = {
user: user,
online: function(status) {
if (status === true) {
settings.online = true;
syncQueue();
} else {
settings.online = false;
};
},
authenticate: function(apiId, apiToken, cb) {
if ( !! apiId && !! apiToken) {
$http.defaults.headers.common = {
'Content-Type': "application/json;charset=utf-8"
};
$http.defaults.headers.common['x-api-user'] = apiId;
$http.defaults.headers.common['x-api-key'] = apiToken;
authenticated = true;
settings.auth.apiId = apiId;
settings.auth.apiToken = apiToken;
settings.online = true;
this.log({}, cb);
} else {
alert('Please enter your ID and Token in settings.')
}
},
log: function(action, cb) {
//push by one buy one if an array passed in.
if (_.isArray(action)) {
action.forEach(function(a) {
settings.sync.queue.push(a);
});
} else {
settings.sync.queue.push(action);
}
save();
syncQueue(cb);
},
fetch:fetch,
settings: settings
};
//load settings if we have them
if (localStorage.getItem(HABIT_MOBILE_SETTINGS)) {
//use extend here to make sure we keep object reference in other angular controllers
_.extend(settings, JSON.parse(localStorage.getItem(HABIT_MOBILE_SETTINGS)));
//if settings were saved while fetch was in process reset the flag.
settings.fetching = false;
//create and load if not
} else {
localStorage.setItem(HABIT_MOBILE_SETTINGS, JSON.stringify(defaultSettings));
_.extend(settings, defaultSettings);
}
//If user does not have ApiID that forward him to settings.
if (!settings.auth.apiId || !settings.auth.apiToken) {
$location.path("/login");
} else {
userServices.authenticate(settings.auth.apiId, settings.auth.apiToken)
}
fetch()
//first we populate user with schema
_.extend(user, schema);
//than we try to load localStorage
if (localStorage.getItem(STORAGE_ID)) {
_.extend(user, JSON.parse(localStorage.getItem(STORAGE_ID)));
}
return userServices;
});

View file

@ -1,58 +0,0 @@
CDV = ( typeof CDV == 'undefined' ? {} : CDV );
var cordova = window.cordova || window.Cordova;
CDV.FB = {
init: function(apiKey, fail) {
// create the fb-root element if it doesn't exist
if (!document.getElementById('fb-root')) {
var elem = document.createElement('div');
elem.id = 'fb-root';
document.body.appendChild(elem);
}
cordova.exec(function() {
var authResponse = JSON.parse(localStorage.getItem('cdv_fb_session') || '{"expiresIn":0}');
if (authResponse && authResponse.expirationTime) {
var nowTime = (new Date()).getTime();
if (authResponse.expirationTime > nowTime) {
// Update expires in information
updatedExpiresIn = Math.floor((authResponse.expirationTime - nowTime) / 1000);
authResponse.expiresIn = updatedExpiresIn;
localStorage.setItem('cdv_fb_session', JSON.stringify(authResponse));
FB.Auth.setAuthResponse(authResponse, 'connected');
}
}
console.log('Cordova Facebook Connect plugin initialized successfully.');
}, (fail?fail:null), 'org.apache.cordova.facebook.Connect', 'init', [apiKey]);
},
login: function(params, cb, fail) {
params = params || { scope: '' };
cordova.exec(function(e) { // login
if (e.authResponse && e.authResponse.expiresIn) {
var expirationTime = e.authResponse.expiresIn === 0
? 0
: (new Date()).getTime() + e.authResponse.expiresIn * 1000;
e.authResponse.expirationTime = expirationTime;
}
localStorage.setItem('cdv_fb_session', JSON.stringify(e.authResponse));
FB.Auth.setAuthResponse(e.authResponse, 'connected');
if (cb) cb(e);
}, (fail?fail:null), 'org.apache.cordova.facebook.Connect', 'login', params.scope.split(',') );
},
logout: function(cb, fail) {
cordova.exec(function(e) {
localStorage.removeItem('cdv_fb_session');
FB.Auth.setAuthResponse(null, 'notConnected');
if (cb) cb(e);
}, (fail?fail:null), 'org.apache.cordova.facebook.Connect', 'logout', []);
},
getLoginStatus: function(cb, fail) {
cordova.exec(function(e) {
if (cb) cb(e);
}, (fail?fail:null), 'org.apache.cordova.facebook.Connect', 'getLoginStatus', []);
},
dialog: function(params, cb, fail) {
cordova.exec(function(e) { // login
if (cb) cb(e);
}, (fail?fail:null), 'org.apache.cordova.facebook.Connect', 'showDialog', [params] );
}
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,377 +0,0 @@
var traverse = require('traverse');
var Stream = require('stream').Stream;
var charm = require('charm');
var deepEqual = require('deep-is');
var exports = module.exports = function (opts_) {
var fn = difflet.bind(null, opts_);
fn.compare = function (prev, next) {
var opts = Object.keys(opts_ || {}).reduce(function (acc, key) {
acc[key] = opts_[key];
return acc;
}, {});
var s = opts.stream = new Stream;
var data = '';
s.write = function (buf) { data += buf };
s.end = function () {};
s.readable = true;
s.writable = true;
difflet(opts, prev, next);
return data;
};
return fn;
};
exports.compare = function (prev, next) {
return exports({}).compare(prev, next);
};
function difflet (opts, prev, next) {
var stream = opts.stream || new Stream;
if (!opts.stream) {
stream.readable = true;
stream.writable = true;
stream.write = function (buf) { this.emit('data', buf) };
stream.end = function () { this.emit('end') };
}
if (!opts) opts = {};
if (opts.start === undefined && opts.stop === undefined) {
var c = charm(stream);
opts.start = function (type) {
c.foreground({
inserted : 'green',
updated : 'blue',
deleted : 'red',
comment : 'cyan',
}[type]);
c.display('bright');
};
opts.stop = function (type) {
c.display('reset');
};
}
var write = function (buf) {
if (opts.write) opts.write(buf, stream)
else stream.write(buf)
};
var commaFirst = opts.comma === 'first';
var stringify = function (node, params) {
return stringifier.call(this, true, node, params || opts);
};
var plainStringify = function (node, params) {
return stringifier.call(this, false, node, params || opts);
};
var levels = 0;
function set (type) {
if (levels === 0) opts.start(type, stream);
levels ++;
}
function unset (type) {
if (--levels === 0) opts.stop(type, stream);
}
function stringifier (insertable, node, opts) {
var indent = opts.indent;
if (insertable) {
var prevNode = traverse.get(prev, this.path || []);
}
var inserted = insertable && prevNode === undefined;
var indentx;
try {
indentx = indent ? Array(
((this.path || []).length + 1) * indent + 1
).join(' ') : '';
} catch (e) {
// at times we get an invalid Array size here and need to prevent crashing
indentx = '';
}
if (commaFirst) indentx = indentx.slice(indent);
if (Array.isArray(node)) {
var updated = (prevNode || traverse.has(prev, this.path))
&& !Array.isArray(prevNode);
if (updated) {
set('updated');
}
if (opts.comment && !Array.isArray(prevNode)) {
indent = 0;
}
this.before(function () {
if (inserted) set('inserted');
if (indent && commaFirst) {
if ((this.path || []).length === 0
|| Array.isArray(this.parent.node)) {
write('[ ');
}
else write('\n' + indentx + '[ ');
}
else if (indent) {
write('[\n' + indentx);
}
else {
write('[');
}
});
this.post(function (child) {
if (!child.isLast && !(indent && commaFirst)) {
write(',');
}
var prev = prevNode && prevNode[child.key];
if (indent && opts.comment && child.node !== prev
&& (typeof child.node !== 'object' || typeof prev !== 'object')
) {
set('comment');
write(' // != ');
traverse(prev).forEach(function (x) {
plainStringify.call(this, x, { indent : 0 });
});
unset('comment');
}
if (!child.isLast) {
if (indent && commaFirst) {
write('\n' + indentx + ', ');
}
else if (indent) {
write('\n' + indentx);
}
}
});
this.after(function () {
if (indent && commaFirst) write('\n' + indentx);
else if (indent) write('\n' + indentx.slice(indent));
write(']');
if (updated) unset('updated');
if (inserted) unset('inserted');
});
}
else if (isRegExp(node)) {
this.block();
if (inserted) {
set('inserted');
write(node.toString());
unset('inserted');
}
else if (insertable && prevNode !== node) {
set('updated');
write(node.toString());
unset('updated');
}
else write(node.toString());
}
else if (typeof node === 'object'
&& node && typeof node.inspect === 'function') {
this.block();
if (inserted) {
set('inserted');
write(node.inspect());
unset('inserted');
}
else if (!(prevNode && typeof prevNode.inspect === 'function'
&& prevNode.inspect() === node.inspect())) {
set('updated');
write(node.inspect());
unset('updated');
}
else write(node.inspect());
}
else if (typeof node == 'object' && node !== null) {
var insertedKey = false;
var deleted = insertable && typeof prevNode === 'object' && prevNode
? Object.keys(prevNode).filter(function (key) {
return !Object.hasOwnProperty.call(node, key);
})
: []
;
this.before(function () {
if (inserted) set('inserted');
write(indent && commaFirst && !this.isRoot
? '\n' + indentx + '{ '
: '{'
);
});
this.pre(function (x, key) {
if (insertable) {
var obj = traverse.get(prev, this.path.concat(key));
if (obj === undefined) {
insertedKey = true;
set('inserted');
}
}
if (indent && !commaFirst) write('\n' + indentx);
plainStringify(key);
write(indent ? ' : ' : ':');
});
this.post(function (child) {
if (!child.isLast && !(indent && commaFirst)) {
write(',');
}
if (child.isLast && deleted.length) {
if (insertedKey) unset('inserted');
insertedKey = false;
}
else if (insertedKey) {
unset('inserted');
insertedKey = false;
}
var prev = prevNode && prevNode[child.key];
if (indent && opts.comment && child.node !== prev
&& (typeof child.node !== 'object' || typeof prev !== 'object')
) {
set('comment');
write(' // != ');
traverse(prev).forEach(function (x) {
plainStringify.call(this, x, { indent : 0 });
});
unset('comment');
}
if (child.isLast && deleted.length) {
if (insertedKey) unset('inserted');
insertedKey = false;
if (indent && commaFirst) {
write('\n' + indentx + ', ')
}
else if (opts.comment && indent) {
write('\n' + indentx);
}
else if (indent) {
write(',\n' + indentx);
}
else write(',');
}
else {
if (!child.isLast) {
if (indent && commaFirst) {
write('\n' + indentx + ', ');
}
}
}
});
this.after(function () {
if (inserted) unset('inserted');
if (deleted.length) {
if (indent && !commaFirst
&& Object.keys(node).length === 0) {
write('\n' + indentx);
}
set('deleted');
deleted.forEach(function (key, ix) {
if (indent && opts.comment) {
unset('deleted');
set('comment');
write('// ');
unset('comment');
set('deleted');
}
plainStringify(key);
write(indent ? ' : ' : ':');
traverse(prevNode[key]).forEach(function (x) {
plainStringify.call(this, x, { indent : 0 });
});
var last = ix === deleted.length - 1;
if (insertable && !last) {
if (indent && commaFirst) {
write('\n' + indentx + ', ');
}
else if (indent) {
write(',\n' + indentx);
}
else write(',');
}
});
unset('deleted');
}
if (commaFirst && indent) {
write(indentx.slice(indent) + ' }');
}
else if (indent) {
write('\n' + indentx.slice(indent) + '}');
}
else write('}');
});
}
else {
var changed = false;
if (inserted) set('inserted');
else if (insertable && !deepEqual(prevNode, node)) {
changed = true;
set('updated');
}
if (typeof node === 'string') {
write('"' + node.toString().replace(/"/g, '\\"') + '"');
}
else if (isRegExp(node)) {
write(node.toString());
}
else if (typeof node === 'function') {
write(node.name
? '[Function: ' + node.name + ']'
: '[Function]'
);
}
else if (node === undefined) {
write('undefined');
}
else if (node === null) {
write('null');
}
else {
write(node.toString());
}
if (inserted) unset('inserted');
else if (changed) unset('updated');
}
}
if (opts.stream) {
traverse(next).forEach(stringify);
}
else process.nextTick(function () {
traverse(next).forEach(stringify);
stream.emit('end');
});
return stream;
}
function isRegExp (node) {
return node instanceof RegExp || (node
&& typeof node.test === 'function'
&& typeof node.exec === 'function'
&& typeof node.compile === 'function'
&& node.constructor && node.constructor.name === 'RegExp'
);
}

File diff suppressed because it is too large Load diff

View file

@ -1,248 +0,0 @@
/*
* swipe 1.0.2 - jQuery UI Widget
* https://github.com/sgentile/jquery.swipe
* Copyright (c) 2011 Steve Gentile (http://twitter.com/stevemgentile)
* Dual licensed under the MIT and GPL licenses
*/
(function ($) {
$.widget("ui.swipe", {
options: {
minSwipeLength: 65, // the shortest distance the user may swipe - the lower the number the more sensitive
minMouseSwipeLength: 300,
preventDefault: false, //used on TouchStart - setting this to true would negate things like button press from working, etc...
includeMouseSwipe: false //set to true to enable for mouse swipe
},
touchesCount: 0, //number of finders
startTouchXPosition: 0, //initial start location x
startTouchYPosition: 0, //initial start location x
currentXTouchPosition: 0,
currentYTouchPosition: 0,
swipeLength: 0,
previousPosition: {},
initialXMousePosition: null, //for mouse
initialYMousePosition: null, //for mouse
swiped: function (e, ui) { },
_create: function () {
var self = this;
var $touch = this.element;
$touch.bind({
"touchstart": function (event) {
//http://stackoverflow.com/questions/671498/jquery-live-removing-iphone-touch-event-attributes
self.touchStart(event.originalEvent);
},
"touchmove": function (event) {
self.touchMove(event.originalEvent);
},
"touchcancel": function (event) {
self.touchCancel(event.originalEvent);
},
"touchend": function (event) {
self.touchEnd(event.originalEvent, function (swipe) {
self._trigger("swiped", event, { swipeDirection: swipe });
});
}
});
//WIndows 8 touch support
if (window.navigator.msPointerEnabled) {
debug.info("msPointerEnabled");
$touch.on({
"MSPointerDown": function (event) {
//event.originalEvent.preventMouseEvent();
debug.info("MSPointerDown");
self.touchStart(event.originalEvent);
},
"MSPointerMove": function (event) {
debug.info("MSPointerMove");
self.touchMove(event.originalEvent);
},
"MSPointerOut": function (event) {
debug.info("MSPointerOut");
self.touchCancel(event.originalEvent);
},
"MSPointerUp": function (event) {
debug.info("MSPointerUp");
self.touchEnd(event.originalEvent, function (swipe) {
debug.info("MSPointerUp touchEnd");
self._trigger("swiped", event, { swipeDirection: swipe });
});
}
});
}
if (self.options.includeMouseSwipe) {
$touch.bind({
"mousedown": function (event) {
self.initialXMousePosition = event.pageX;
self.initialYMousePosition = event.pageY;
//event.stopPropagation();
event.preventDefault();
},
"mouseup": function (event) {
var x = event.pageX;
var y = event.pageY;
//event.stopPropagation();
event.preventDefault();
var mouseSwipeLength = self.calculateSwipeAngle(self.initialXMousePosition, x, self.initialYMousePosition, y);
// if the user swiped more than the minimum length, perform the appropriate action
if (mouseSwipeLength >= self.options.minMouseSwipeLength) {
var swipeAngle = self.getSwipeAngle(self.initialXMousePosition, x, self.initialYMousePosition, y);
var swipeDirection = self.determineSwipeDirection(swipeAngle);
if (swipeDirection != null) {
self._trigger('swiped', event, { swipeDirection: swipeDirection });
}
}
self.initialXMousePosition = null;
self.initialYMousePosition = null;
}
});
}
},
touchStart: function (event) {
var self = this;
if (self.options.preventDefault) {
// disable the standard ability to select the touched object
event.preventDefault();
}
if (window.navigator.msPointerEnabled) {
var currentPointers = event.getPointerList();
debug.info("touchStart touchesCount: " + currentPointers.length);
self.touchesCount = currentPointers.length;
debug.info('touch start length: ' + currentPointers.length);
if (currentPointers.length === 1) {
self.startTouchXPosition = event.pageX;
self.startTouchYPosition = event.pageY;
debug.info("touchstart " + self.startTouchXPosition + " " + self.startTouchYPosition);
} else {
self.touchCancel(event);
}
} else {
// get the total number of fingers touching the screen
self.touchesCount = event.touches.length;
// since we're looking for a swipe (single finger) and not a gesture (multiple fingers),
// check that only one finger was used
if (self.touchesCount == 1) {
// get the coordinates of the touch
self.startTouchXPosition = event.touches[0].pageX;
self.startTouchYPosition = event.touches[0].pageY;
} else {
// more than one finger touched so cancel
self.touchCancel(event);
}
}
},
touchMove: function (event) {
var self = this;
event.preventDefault();
if (window.navigator.msPointerEnabled) {
//var currentPointers = event.getPointerList();
debug.info('touch move length: ' + self.touchesCount);
if (self.touchesCount === 1) {
debug.info('touchmove');
self.currentXTouchPosition = event.pageX;
self.currentYTouchPosition = event.pageY;
} else {
self.touchCancel(event);
}
} else {
if (event.touches.length == 1) {
self.currentXTouchPosition = event.touches[0].pageX;
self.currentYTouchPosition = event.touches[0].pageY;
} else {
self.touchCancel(event);
}
}
},
touchEnd: function (event, callback) {
var self = this;
event.preventDefault();
if (window.navigator.msPointerEnabled) {
debug.info('calculate swipe length');
self.swipeLength = self.calculateSwipeAngle(self.startTouchXPosition, self.currentXTouchPosition, self.startTouchYPosition, self.currentYTouchPosition);
debug.info('swipe length ' + self.swipeLength);
// if the user swiped more than the minimum length, perform the appropriate action
if (self.swipeLength >= self.options.minSwipeLength) {
var swipeAngle = self.getSwipeAngle(self.startTouchXPosition, self.currentXTouchPosition, self.startTouchYPosition, self.currentYTouchPosition);
var swipeDirection = self.determineSwipeDirection(swipeAngle);
callback(swipeDirection); // callback with the swipe direction
self.touchCancel(event); // reset the variables
} else {
self.touchCancel(event);
}
} else {
// check to see if more than one finger was used and that there is an ending coordinate
if (self.touchesCount == 1 && self.currentXTouchPosition != 0) {
debug.info('calculate swipe length');
self.swipeLength = self.calculateSwipeAngle(self.startTouchXPosition, self.currentXTouchPosition, self.startTouchYPosition, self.currentYTouchPosition);
debug.info('swipe length ' + self.swipeLength);
// if the user swiped more than the minimum length, perform the appropriate action
if (self.swipeLength >= self.options.minSwipeLength) {
var swipeAngle = self.getSwipeAngle(self.startTouchXPosition, self.currentXTouchPosition, self.startTouchYPosition, self.currentYTouchPosition);
var swipeDirection = self.determineSwipeDirection(swipeAngle);
callback(swipeDirection); // callback with the swipe direction
self.touchCancel(event); // reset the variables
} else {
self.touchCancel(event);
}
} else {
self.touchCancel(event);
}
}
},
touchCancel: function (event) {
var self = this;
// reset the variables back to default values
self.touchesCount = 0;
self.startTouchXPosition = 0;
self.startTouchYPosition = 0;
self.currentXTouchPosition = 0;
self.currentYTouchPosition = 0;
self.swipeLength = 0;
},
calculateSwipeAngle: function (startXPos, currentXPos, startYPos, currentYPos) {
// determine the length of the swipe using distance formula
return Math.round(Math.sqrt(Math.pow(currentXPos - startXPos, 2) + Math.pow(currentYPos - startYPos, 2)));
},
getSwipeAngle: function (startXPos, currentXPos, startYPos, currentYPos) {
var x = startXPos - currentXPos;
var y = currentYPos - startYPos;
var r = Math.atan2(y, x); //angle in radians (Cartesian system)
var swipeAngle = Math.round(r * 180 / Math.PI); //angle in degrees
if (swipeAngle < 0) { swipeAngle = 360 - Math.abs(swipeAngle); }
return swipeAngle;
},
determineSwipeDirection: function (swipeAngle) {
if ((swipeAngle <= 45) && (swipeAngle >= 0)) {
return 'left';
} else if ((swipeAngle <= 360) && (swipeAngle >= 315)) {
return 'left';
} else if ((swipeAngle >= 135) && (swipeAngle <= 225)) {
return 'right';
} else if ((swipeAngle > 45) && (swipeAngle < 135)) {
return 'down';
} else {
return 'up';
}
}
});
})(jQuery);

File diff suppressed because one or more lines are too long

View file

@ -1,35 +0,0 @@
<div ng-controller="CharacterCtrl">
<figure class="herobox"
data-name="{{username(user.auth)}}"
data-level="{{user.stats.lvl}}"
data-checkuser="isUser"
>
<div class='character-sprites'>
<span class='{{user.preferences.gender}}_skin_{{user.preferences.skin}}'></span>
<span class='{{user.preferences.gender}}_hair_{{user.preferences.hair}}'></span>
<span class="{{equipped(user, 'armor')}}"></span>
<span class="{{equipped(user, 'head')}}"></span>
<span class="{{user.preferences.gender}}_head_0"></span>
<span class='{{user.preferences.gender}}_shield_{{user.items.shield}}'></span>
<span class='{{user.preferences.gender}}_weapon_{{user.items.weapon}}'></span>
</div>
</figure>
<div class="user">
{{user.auth.username}}<br>
level {{user.stats.lvl}}
</div>
<div style="clear:both"></div>
<div class="meter animate">
<span style="width: {{hpPercent(user.stats.hp)}}%"><span></span></span>
</div>
<div class="meter animate orange">
<span style="width: {{expPercent(user.stats.exp, user.stats.lvl)}}%"><span></span></span>
</div>
</div>
<div ng-controller="userAvatarCtrl"></div>

View file

@ -1,61 +0,0 @@
<div ng-controller="StatsCtrl"></div>
<div ng-controller="TaskDetailsCtrl">
<!-- Details Page -->
<div ng-hide="editing">
<a ng-click='goBack()'>Back</a> | <a ng-click="edit()">Edit</a>
<h2><span ng-show="task.completed"></span>{{task.text}}</h2>
<p>{{task.notes}}</p>
<!-- Habits -->
<span ng-show="task.type == 'habit'" ng-cloak>
<input type="button" value="+" ng-click="score(task,'up')"/>
<input type="button" value="-" ng-click="score(task,'down')"/>
</span>
{{task.title}}
<!-- Daily, Todo -->
<input class="toggle" type="checkbox" ng-model="task.completed" ng-show="task.type == 'daily' || task.type == 'todo'" ng-cloak />
<input type="button" value="Buy ({{task.value}})" ng-show="task.type == 'reward'" ng-cloak />
<!-- Rewards -->
<span></span>
</div>
<!-- Edit Page -->
<div ng-show="editing">
<a ng-click='cancel()'>Cancel</a> | <a ng-click='save()'>Save</a> | <a ng-click='delete()'>Delete</a>
Title: <input type='input' ng-model="task.text" /><br/>
Notes: <textarea ng-model="task.notes" />
<!-- Habits -->
<span ng-show="task.type == 'habit'" ng-cloak>
<input type="checkbox" ng-model='task.up'> Up<br/>
<input type="checkbox" ng-model='task.down'> Down
</span>
<!-- Dailies -->
<div ng-show="task.type == 'daily'">
TODO: Repeat
</div>
<!-- Todos -->
<div ng-show="task.type == 'todo'">
TODO: Due Date
</div>
<!-- Rewards -->
<div ng-hide="task.type == 'reward'">
TODO: Difficulty
</div>
</div>
</div>

View file

@ -1,33 +0,0 @@
<div ng-controller="LoginCtrl">
<div ng-controller="CharacterCtrl">
<div class="herobox">
<div class='character-sprites'>
<span class='{{user.preferences.gender}}_skin_{{user.preferences.skin}}'></span>
<span class='{{user.preferences.gender}}_hair_{{user.preferences.hair}}'></span>
<span class="{{equipped(user, 'armor')}}"></span>
<span class="{{equipped(user, 'head')}}"></span>
<span class="{{user.preferences.gender}}_head_0"></span>
<span class='{{user.preferences.gender}}_shield_{{user.items.shield}}'></span>
<span class='{{user.preferences.gender}}_weapon_{{user.items.weapon}}'></span>
</div>
</div>
<div class="user">
{{user.auth.local.username}}<br>
level {{user.stats.lvl}}
</div>
<div style="clear:both"></div>
<div class="meter animate">
<span style="width: {{hpPercent(user.stats.hp)}}%"><span></span></span>
</div>
<div class="meter animate orange">
<span style="width: {{expPercent(user.stats.exp, user.stats.lvl)}}%"><span></span></span>
</div>
</div>
</div>

View file

@ -1,11 +0,0 @@
<div class='login-page' ng-controller='AuthCtrl'>
<div style="width:200px; margin:0 auto">
<form ng-submit="apiLogin()" id="apiLoginForm">
<label for="uuid">UUID</label><input type='text' id="uuid1" ng-model="uuid" required/>
<label for="apiToken">API Token</label><input type='text' id="apiToken1" ng-model="apiToken" required/><br />
<input type='submit' value="Submit" />
</form>
</div>
</div>
</div>

View file

@ -1,72 +0,0 @@
<div style="margin:10px">
<ul class="nav nav-tabs game-tabs">
<li class="active">
<a data-toggle="tab" data-target="#profile-customize"><i class="icon-user"></i> Profile</a>
</li>
<li>
<a id="party-tab-link" data-toggle="tab" data-target="#profile-groups"><i class="icon-heart"></i> Groups</a>
</li>
<!--$1bv-->
<li>
<a data-toggle="tab" data-target="#profile-inventory"><i class="icon-gift"></i> Inventory</a>
</li>
<li>
<a data-toggle="tab" data-target="#profile-stable"><i class="icon-leaf"></i> Stable</a>
</li>
<!--$$1bv-->
<li>
<a data-toggle="tab" data-target="#profile-tavern"><i class="icon-eye-close"></i> Tavern</a>
</li>
<li>
<a data-toggle="tab" data-target="#profile-achievements"><i class="icon-certificate"></i> Achievements</a>
</li>
<li>
<a data-toggle="tab" data-target="#profile-settings"><i class="icon-wrench"></i> Settings</a>
</li>
</ul>
</div>
<div class="tab-content" style="margin:10px">
<div class="row-fluid">
<div class="span4 border-right">
<div ng-controller="userAvatarCtrl" class="userAvatar">
<div>
<menu type="list">
<li class="customize-menu">
<menu label="Head">
<button type="button" class="m_head_0 customize-option" data-value="m" ng-click="changeSex('m')"></button>
<button type="button" class="f_head_0 customize-option" data-value="f" ng-click="changeSex('f')"></button>
</menu>
</li>
<li class="customize-menu">
<menu label="Hair">
<button type="button" class="{{user.preferences.gender}}_hair_blond customize-option" data-value="blond" ng-click="changeHair('blond')"></button>
<button type="button" class="{{user.preferences.gender}}_hair_black customize-option" data-value="black" ng-click="changeHair('black')"></button>
<button type="button" class="{{user.preferences.gender}}_hair_brown customize-option" data-value="brown" ng-click="changeHair('brown')"></button>
<button type="button" class="{{user.preferences.gender}}_hair_white customize-option" data-value="white" ng-click="changeHair('white')"></button>
</menu>
</li>
<li class="customize-menu">
<menu label="Skin">
<button type="button" class="{{user.preferences.gender}}_skin_dead customize-option" data-value="dead" ng-click="changeSkin('dead')"></button>
<button type="button" class="{{user.preferences.gender}}_skin_orc customize-option" data-value="orc" ng-click="changeSkin('orc')"></button>
<button type="button" class="{{user.preferences.gender}}_skin_asian customize-option" data-value="asian" ng-click="changeSkin('asian')"></button>
<button type="button" class="{{user.preferences.gender}}_skin_black customize-option" data-value="black" ng-click="changeSkin('black')"></button>
<button type="button" class="{{user.preferences.gender}}_skin_white customize-option" data-value="white" ng-click="changeSkin('white')"></button>
</menu>
</li>
<li class="customize-menu">
<menu label="Clothing" ng-show="user.preferences.gender == 'f'">
<button type="button" class="f_armor_0_v1 customize-option" data-value="v1" ng-click="changeArmor('v1')"></button>
<button type="button" class="f_armor_0_v2 customize-option" data-value="v2" ng-click="changeArmor('v2')"></button>
</menu>
</li>
</menu>
</div>
</div>
</div>
</div>
</div>

View file

@ -1,31 +0,0 @@
<div ng-controller="CharacterCtrl">
<div class="herobox">
<div class='character-sprites' ng-click="showUserAvatar()">
<span class='{{user.preferences.gender}}_skin_{{user.preferences.skin}}'></span>
<span class='{{user.preferences.gender}}_hair_{{user.preferences.hair}}'></span>
<span class="{{equipped(user, 'armor')}}"></span>
<span class="{{equipped(user, 'head')}}"></span>
<span class="{{user.preferences.gender}}_head_0"></span>
<span class='{{user.preferences.gender}}_shield_{{user.items.shield}}'></span>
<span class='{{user.preferences.gender}}_weapon_{{user.items.weapon}}'></span>
</div>
</div>
<div class="user">
{{user.auth.local.username}}<br>
level {{user.stats.lvl}}<br>
Gold: {{user.stats.gp | gold}}
Silver: {{user.stats.gp | silver}}
</div>
<div style="clear:both"></div>
<div class="meter animate">
<span style="width: {{hpPercent(user.stats.hp)}}%"><span></span></span>
</div>
<div class="meter animate orange">
<span style="width: {{expPercent(user.stats.exp, user.stats.lvl)}}%"><span></span></span>
</div>
</div>

View file

@ -1,7 +0,0 @@
<div ng-controller="SettingsCtrl">
<div>Id:<input type="text" ng-model="settings.auth.apiId">
Token:<input type="text" ng-model="settings.auth.apiToken">
<input type="button" value="Save" ng-click="auth(settings.auth.apiId,settings.auth.apiToken)">
<input type="button" value="RESET APPLICATION" ng-click="resetApp()">
</div>
</div>

View file

@ -1,22 +0,0 @@
{
"name": "yeoman",
"version": "0.0.0",
"dependencies": {
"angular": "~1.0.5",
"jquery": "~1.9.1",
"json3": "~3.2.4",
"es5-shim": "~2.0.5",
"angular-resource": "~1.0.5",
"angular-cookies": "~1.0.5",
"angular-sanitize": "~1.0.5",
"underscore": "*",
"moment": "*",
"habitrpg-shared": "git://github.com/HabitRPG/habitrpg-shared.git",
"hammerjs": "~1.0.5",
"angular-hammer": "~1.0.1"
},
"devDependencies": {
"angular-mocks": "~1.0.5",
"angular-scenario": "~1.0.5"
}
}

View file

@ -1,33 +0,0 @@
{
"name": "yeoman",
"version": "0.0.0",
"dependencies": {
"express": "~3.1.0"
},
"devDependencies": {
"grunt": "0.4.0rc7",
"grunt-contrib-copy": "0.4.0rc7",
"grunt-contrib-concat": "0.1.2rc6",
"grunt-contrib-coffee": "0.4.0rc7",
"grunt-contrib-uglify": "0.1.1rc6",
"grunt-contrib-compass": "0.1.1rc8",
"grunt-contrib-jshint": "0.1.1rc6",
"grunt-contrib-mincss": "0.4.0rc7",
"grunt-contrib-connect": "0.1.1rc6",
"grunt-contrib-clean": "0.4.0rc6",
"grunt-contrib-htmlmin": "0.1.1rc7",
"grunt-contrib-imagemin": "0.1.1rc8",
"grunt-contrib-livereload": "0.1.0rc8",
"grunt-bower-hooks": "~0.2.0",
"grunt-usemin": "~0.1.7",
"grunt-regarde": "~0.1.1",
"gruntacular": "~0.1.1",
"grunt-open": "~0.1.0",
"matchdep": "~0.1.1",
"grunt-google-cdn": "~0.1.0",
"grunt-ngmin": "~0.0.1"
},
"engines": {
"node": ">=0.8.0"
}
}

View file

@ -0,0 +1,111 @@
'use strict';
habitrpg.controller('TasksCtrl', function TasksCtrl($scope, $rootScope, $location, filterFilter, User, Algos, Helpers, Notification) {
$scope.user = User.user;
$scope.score = function (task, direction) {
//save current stats to compute the difference after scoring.
var statsDiff = {};
var oldStats = _.clone(User.user.stats);
Algos.score(User.user, task, direction);
//compute the stats change.
_.each(oldStats, function (value, key) {
var newValue = User.user.stats[key];
if (newValue !== value) {
statsDiff[key] = newValue - value;
}
});
//notify user if there are changes in stats.
if (Object.keys(statsDiff).length > 0) {
// Notification.push({type: 'stats', stats: statsDiff});
}
User.log({op: 'score', task: task, dir: direction});
};
$scope.save = function(task) {
var ops = ([
{op: 'set', path: "tasks." + task.id + ".text", value: task.text},
{op: 'set', path: "tasks." + task.id + ".notes", value: task.notes},
{op: 'set', path: "tasks." + task.id + ".up", value: task.up},
{op: 'set', path: "tasks." + task.id + ".down", value: task.down},
{op: 'set', path: "tasks." + task.id + ".priority", value: task.priority},
{op: 'set', path: "tasks." + task.id + ".date", value: task.date},
{op: 'set', path: "tasks." + task.id + ".price", value: task.price},
])
_.each(task.tags, function(el, key, list) {
ops.push({op: 'set', path: "tasks." + task.id + ".tags." + key, value: el})
})
_.each(task.repeat, function(el, key, list) {
ops.push({op: 'set', path: "tasks." + task.id + ".repeat." + key, value: el})
})
User.log(ops)
task.editing = false
}
$scope.getRepeat = function(task, repeat) {
var enabled = '';
_.each(task.repeat, function(el, key, list) {
if (key == repeat && el == true) {
enabled = true
}
})
if (enabled) {
return true
}else{
return false
}
}
$scope.setRepeat = function(task, repeat) {
if (typeof task.repeat == 'undefined') {
var obj = {}
obj[repeat] = true;
task.repeat = {}
task.repeat = obj
return true
}
if (!task.repeat[repeat]) {
task.repeat[repeat] = true
}else{
task.repeat[repeat] = false
}
}
$scope.addTag = function(task, tag) {
var obj = {}
obj[tag] = true
task.tags.push(obj)
}
$scope.toggleTag = function(task, tag) {
var obj = {}
if (typeof task.tags != 'undefined') {
if (!task.tags[tag]) {
task.tags[tag] = false;
}else{
task.tags[tag] = true
}
}else{
task.tags = {}
task.tags[tag] = true
}
}
});

View file

@ -55,19 +55,18 @@ habitrpg.directive('whenScrolled', function() {
* Add sortable
*/
habitrpg.directive('sort', function (User) {
return ['$scope', '$rootScope', 'element', 'attrs', 'ngModel',
function($scope, $rootScope, element, attrs, ngModel) {
$(element).sortable({
axis: "y",
start: function (event, ui) {
ui.item.data('startIndex', ui.item.index());
},
stop: function (event, ui) {
var taskType = $rootScope.taskContext.type;
var startIndex = ui.item.data('startIndex');
var task = User.user[taskType][startIndex];
User.log({op: 'sortTask', data: task, from: startIndex, to: ui.item.index()});
}
});
return ['$scope', 'element', 'attrs', 'ngModel', function($scope, element, attrs, ngModel) {
$(element).sortable({
axis: "y",
start: function (event, ui) {
ui.item.data('startIndex', ui.item.index());
},
stop: function (event, ui) {
var taskType = angular.element(ui.item[0]).scope().task.type + 's'
var startIndex = ui.item.data('startIndex');
var task = User.user[taskType][startIndex];
User.log({op: 'sortTask', data: task, from: startIndex, to: ui.item.index()});
}
});
}]
});
});

View file

@ -6,6 +6,11 @@ html
script(type='text/javascript').
window.env = !{JSON.stringify(env)};
style.
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none;
}
// CSS
link(rel='stylesheet', href='/bower_components/bootstrap/docs/assets/css/bootstrap.css')
link(rel='stylesheet', href='/bower_components/bootstrap/docs/assets/css/bootstrap-responsive.css')
@ -56,7 +61,7 @@ html
meta(name='viewport', content='width=device-width')
meta(name='apple-mobile-web-app-capable', content='yes')
body(ng-app="habitrpg", ng-controller="RootCtrl")
body(ng-app="habitrpg", ng-controller="RootCtrl", ng-cloak)
include ./shared/modals/index
include ./shared/header/header