mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-05-20 04:38:55 +00:00
Merge pull request #4713 from HabitRPG/lefnire/interactive-tour
Interactive Tour
This commit is contained in:
commit
de67f44e1f
13 changed files with 253 additions and 357 deletions
127
common/dist/scripts/habitrpg-shared.js
vendored
127
common/dist/scripts/habitrpg-shared.js
vendored
|
|
@ -176,7 +176,7 @@ gear = {
|
|||
0: {
|
||||
text: t('weaponWarrior0Text'),
|
||||
notes: t('weaponWarrior0Notes'),
|
||||
value: 0
|
||||
value: 1
|
||||
},
|
||||
1: {
|
||||
text: t('weaponWarrior1Text'),
|
||||
|
|
@ -4574,7 +4574,7 @@ api.userDefaults = {
|
|||
value: 0,
|
||||
up: true,
|
||||
down: false,
|
||||
attribute: 'per'
|
||||
attribute: 'str'
|
||||
}, {
|
||||
type: 'habit',
|
||||
text: t('defaultHabit2Text'),
|
||||
|
|
@ -4582,7 +4582,7 @@ api.userDefaults = {
|
|||
value: 0,
|
||||
up: false,
|
||||
down: true,
|
||||
attribute: 'con'
|
||||
attribute: 'str'
|
||||
}, {
|
||||
type: 'habit',
|
||||
text: t('defaultHabit3Text'),
|
||||
|
|
@ -4593,52 +4593,7 @@ api.userDefaults = {
|
|||
attribute: 'str'
|
||||
}
|
||||
],
|
||||
dailys: [
|
||||
{
|
||||
type: 'daily',
|
||||
text: t('defaultDaily1Text'),
|
||||
notes: t('defaultDaily1Notes'),
|
||||
value: 0,
|
||||
completed: false,
|
||||
repeat: repeat,
|
||||
attribute: 'per'
|
||||
}, {
|
||||
type: 'daily',
|
||||
text: t('defaultDaily2Text'),
|
||||
notes: t('defaultDaily2Notes'),
|
||||
value: 3,
|
||||
completed: false,
|
||||
repeat: repeat,
|
||||
attribute: 'con'
|
||||
}, {
|
||||
type: 'daily',
|
||||
text: t('defaultDaily3Text'),
|
||||
notes: t('defaultDaily3Notes'),
|
||||
value: -10,
|
||||
completed: false,
|
||||
repeat: repeat,
|
||||
attribute: 'int'
|
||||
}, {
|
||||
type: 'daily',
|
||||
text: t('defaultDaily4Text'),
|
||||
notes: t('defaultDaily4Notes'),
|
||||
checklist: [
|
||||
{
|
||||
completed: true,
|
||||
text: t('defaultDaily4Checklist1')
|
||||
}, {
|
||||
completed: false,
|
||||
text: t('defaultDaily4Checklist2')
|
||||
}, {
|
||||
completed: false,
|
||||
text: t('defaultDaily4Checklist3')
|
||||
}
|
||||
],
|
||||
completed: false,
|
||||
repeat: repeat,
|
||||
attribute: 'str'
|
||||
}
|
||||
],
|
||||
dailys: [],
|
||||
todos: [
|
||||
{
|
||||
type: 'todo',
|
||||
|
|
@ -4646,81 +4601,9 @@ api.userDefaults = {
|
|||
notes: t('defaultTodoNotes'),
|
||||
completed: false,
|
||||
attribute: 'int'
|
||||
}, {
|
||||
type: 'todo',
|
||||
text: t('defaultTodo2Text'),
|
||||
notes: t('defaultTodoNotes'),
|
||||
checklist: [
|
||||
{
|
||||
completed: false,
|
||||
text: t('defaultTodo2Checklist1')
|
||||
}, {
|
||||
completed: false,
|
||||
text: t('defaultTodo2Checklist2')
|
||||
}, {
|
||||
completed: false,
|
||||
text: t('defaultTodo2Checklist3')
|
||||
}
|
||||
],
|
||||
completed: false,
|
||||
attribute: 'per'
|
||||
}, {
|
||||
type: 'todo',
|
||||
text: t('defaultTodo3Text'),
|
||||
notes: t('defaultTodoNotes'),
|
||||
checklist: [
|
||||
{
|
||||
completed: false,
|
||||
text: t('defaultTodo3Checklist1')
|
||||
}, {
|
||||
completed: false,
|
||||
text: t('defaultTodo3Checklist2')
|
||||
}, {
|
||||
completed: false,
|
||||
text: t('defaultTodo3Checklist3')
|
||||
}
|
||||
],
|
||||
completed: false,
|
||||
attribute: 'per'
|
||||
}, {
|
||||
type: 'todo',
|
||||
text: t('defaultTodo4Text'),
|
||||
notes: t('defaultTodoNotes'),
|
||||
checklist: [
|
||||
{
|
||||
completed: false,
|
||||
text: t('defaultTodo4Checklist1')
|
||||
}, {
|
||||
completed: false,
|
||||
text: t('defaultTodo4Checklist2')
|
||||
}, {
|
||||
completed: false,
|
||||
text: t('defaultTodo4Checklist3')
|
||||
}
|
||||
],
|
||||
completed: false,
|
||||
attribute: 'per'
|
||||
}, {
|
||||
type: 'todo',
|
||||
text: t('defaultTodo5Text'),
|
||||
notes: t('defaultTodoNotes'),
|
||||
completed: false,
|
||||
attribute: 'per'
|
||||
}
|
||||
],
|
||||
rewards: [
|
||||
{
|
||||
type: 'reward',
|
||||
text: t('defaultReward1Text'),
|
||||
notes: t('defaultReward1Notes'),
|
||||
value: 20
|
||||
}, {
|
||||
type: 'reward',
|
||||
text: t('defaultReward2Text'),
|
||||
notes: t('defaultReward2Notes'),
|
||||
value: 10
|
||||
}
|
||||
],
|
||||
rewards: [],
|
||||
tags: [
|
||||
{
|
||||
name: t('defaultTag1')
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"defaultHabit1Text": "1h Productive Work",
|
||||
"defaultHabit1Notes": "When you create a new Habit, you can click the Edit icon and choose for it to represent a positive habit, a negative habit, or both. For some Habits, like this one, it only makes sense to gain points.",
|
||||
"defaultHabit1Text": "Good Habit",
|
||||
"defaultHabit1Notes": " ",
|
||||
|
||||
"defaultHabit2Text": "Eat Junk Food",
|
||||
"defaultHabit2Notes": "For others, it only makes sense to *lose* points.",
|
||||
|
||||
"defaultHabit3Text": "Take The Stairs",
|
||||
"defaultHabit3Notes": "For the rest, both + and - make sense (stairs = gain, elevator = lose).",
|
||||
"defaultHabit2Text": "Bad Habit",
|
||||
"defaultHabit2Notes": " ",
|
||||
|
||||
"defaultHabit3Text": "Good or Bad Habit",
|
||||
"defaultHabit3Notes": " ",
|
||||
|
||||
"defaultDaily1Text": "1h Personal Project",
|
||||
"defaultDaily1Notes": "All tasks default to yellow when they are created. This means you will take only moderate damage when they are missed and will gain only a moderate reward when they are completed.",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"payNote": "Note: PayPal sometimes takes a long time to clear. We recommend paying with card.",
|
||||
"card": "Card",
|
||||
"paymentMethods": "Payment Methods:",
|
||||
|
||||
"welcomeHabit": "Welcome to HabitRPG",
|
||||
"welcomeHabitT1": "Welcome to HabitRPG, a habit tracker that treats your tasks like a Role Playing Game. I'm",
|
||||
"welcomeHabitT2": "your guide!",
|
||||
|
|
@ -61,5 +62,17 @@
|
|||
"spells": "Spells",
|
||||
"spellsText": "You can now unlock class-specific spells. You'll see your first at level 11. Your mana replenishes 10 points per day, plus 1 point per completed ",
|
||||
"toDo": "To-Do",
|
||||
"moreClass": "For more information on the class-system, see"
|
||||
"moreClass": "For more information on the class-system, see",
|
||||
|
||||
"tourWelcome": "Welcome to Habitica! This is your To-Do list. Check off a task!",
|
||||
"tourExp": "Great job! Checking off a task gives you Experience and Gold!",
|
||||
"tourDailies": "This column is for Daily tasks. Enter a task you should do every day! <b>Sample Dailies</b>: <b>Make Bed</b>, <b>Floss</b>, <b>Check Work Email</b>",
|
||||
"tourCron": "Splendid! Your Dailies will reset every day.",
|
||||
"tourHP": "Watch out! If you don't complete a Daily by midnight, it will hurt you!",
|
||||
"tourHabits": "This column is for good and bad Habits that you do many times a day! Click the pencil to edit the names.<ul><li><b>Sample Good Habits</b>: <b>Eat a vegetable</b>, <b>15 minutes productive work</b></li><li><b>Sample Bad Habits</b>: <b>Smoke</b>, <b>Procrastinate</b></li><li><b>Sample Good or Bad Habits</b>: <b>Took Stairs/Elevator</b>, <b>Drank Water/Soda</b>",
|
||||
"tourStats": "Good Habits add Experience and Gold! Bad Habits remove health.",
|
||||
"tourGP": "Buy the Training Sword with the gold you just earned!",
|
||||
"tourAvatar": "Now your avatar has the Training Sword. Click on your avatar to customize it!",
|
||||
"tourScrollDown": "Be sure to scroll all the way down to see all the options! Click on your avatar again to return to the tasks page.",
|
||||
"tourMuchMore": "When you're done with tasks, you can form a Party with friends, chat in the shared-interest Guilds, join Challenges, and more!"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ gear =
|
|||
0:
|
||||
text: t('weaponBase0Text'), notes: t('weaponBase0Notes'), value:0
|
||||
warrior:
|
||||
0: text: t('weaponWarrior0Text'), notes: t('weaponWarrior0Notes'), value:0
|
||||
0: text: t('weaponWarrior0Text'), notes: t('weaponWarrior0Notes'), value:1
|
||||
1: text: t('weaponWarrior1Text'), notes: t('weaponWarrior1Notes', {str: 3}), str: 3, value:20
|
||||
2: text: t('weaponWarrior2Text'), notes: t('weaponWarrior2Notes', {str: 6}), str: 6, value:30
|
||||
3: text: t('weaponWarrior3Text'), notes: t('weaponWarrior3Notes', {str: 9}), str: 9, value:45
|
||||
|
|
@ -1654,29 +1654,29 @@ _.each api.subscriptionBlocks, (b,k)->b.key = k
|
|||
repeat = {m:true,t:true,w:true,th:true,f:true,s:true,su:true}
|
||||
api.userDefaults =
|
||||
habits: [
|
||||
{type: 'habit', text: t('defaultHabit1Text'), notes: t('defaultHabit1Notes'), value: 0, up: true, down: false, attribute: 'per' }
|
||||
{type: 'habit', text: t('defaultHabit2Text'), notes: t('defaultHabit2Notes'), value: 0, up: false, down: true, attribute: 'con'}
|
||||
{type: 'habit', text: t('defaultHabit1Text'), notes: t('defaultHabit1Notes'), value: 0, up: true, down: false, attribute: 'str' }
|
||||
{type: 'habit', text: t('defaultHabit2Text'), notes: t('defaultHabit2Notes'), value: 0, up: false, down: true, attribute: 'str'}
|
||||
{type: 'habit', text: t('defaultHabit3Text'), notes: t('defaultHabit3Notes'), value: 0, up: true, down: true, attribute: 'str'}
|
||||
]
|
||||
|
||||
dailys: [
|
||||
{type: 'daily', text: t('defaultDaily1Text'), notes: t('defaultDaily1Notes'), value: 0, completed: false, repeat: repeat, attribute: 'per' }
|
||||
{type: 'daily', text: t('defaultDaily2Text'), notes: t('defaultDaily2Notes'), value: 3, completed: false, repeat: repeat, attribute: 'con' }
|
||||
{type: 'daily', text: t('defaultDaily3Text'), notes: t('defaultDaily3Notes'), value: -10, completed: false, repeat: repeat, attribute: 'int' }
|
||||
{type: 'daily', text: t('defaultDaily4Text'), notes: t('defaultDaily4Notes'), checklist: [{completed: true, text: t('defaultDaily4Checklist1') }, {completed: false, text: t('defaultDaily4Checklist2')}, {completed: false, text: t('defaultDaily4Checklist3')}], completed: false, repeat: repeat, attribute: 'str' }
|
||||
# {type: 'daily', text: t('defaultDaily1Text'), notes: t('defaultDaily1Notes'), value: 0, completed: false, repeat: repeat, attribute: 'per' }
|
||||
# {type: 'daily', text: t('defaultDaily2Text'), notes: t('defaultDaily2Notes'), value: 3, completed: false, repeat: repeat, attribute: 'con' }
|
||||
# {type: 'daily', text: t('defaultDaily3Text'), notes: t('defaultDaily3Notes'), value: -10, completed: false, repeat: repeat, attribute: 'int' }
|
||||
# {type: 'daily', text: t('defaultDaily4Text'), notes: t('defaultDaily4Notes'), checklist: [{completed: true, text: t('defaultDaily4Checklist1') }, {completed: false, text: t('defaultDaily4Checklist2')}, {completed: false, text: t('defaultDaily4Checklist3')}], completed: false, repeat: repeat, attribute: 'str' }
|
||||
]
|
||||
|
||||
todos: [
|
||||
{type: 'todo', text: t('defaultTodo1Text'), notes: t('defaultTodoNotes'), completed: false, attribute: 'int' }
|
||||
{type: 'todo', text: t('defaultTodo2Text'), notes: t('defaultTodoNotes'), checklist: [{completed: false, text: t('defaultTodo2Checklist1') }, {completed: false, text: t('defaultTodo2Checklist2')}, {completed: false, text: t('defaultTodo2Checklist3')}], completed: false, attribute: 'per' }
|
||||
{type: 'todo', text: t('defaultTodo3Text'), notes: t('defaultTodoNotes'), checklist: [{completed: false, text: t('defaultTodo3Checklist1') }, {completed: false, text: t('defaultTodo3Checklist2')}, {completed: false, text: t('defaultTodo3Checklist3')}], completed: false, attribute: 'per' }
|
||||
{type: 'todo', text: t('defaultTodo4Text'), notes: t('defaultTodoNotes'), checklist: [{completed: false, text: t('defaultTodo4Checklist1') }, {completed: false, text: t('defaultTodo4Checklist2')}, {completed: false, text: t('defaultTodo4Checklist3')}], completed: false, attribute: 'per' }
|
||||
{type: 'todo', text: t('defaultTodo5Text'), notes: t('defaultTodoNotes'), completed: false, attribute: 'per' }
|
||||
# {type: 'todo', text: t('defaultTodo2Text'), notes: t('defaultTodoNotes'), checklist: [{completed: false, text: t('defaultTodo2Checklist1') }, {completed: false, text: t('defaultTodo2Checklist2')}, {completed: false, text: t('defaultTodo2Checklist3')}], completed: false, attribute: 'per' }
|
||||
# {type: 'todo', text: t('defaultTodo3Text'), notes: t('defaultTodoNotes'), checklist: [{completed: false, text: t('defaultTodo3Checklist1') }, {completed: false, text: t('defaultTodo3Checklist2')}, {completed: false, text: t('defaultTodo3Checklist3')}], completed: false, attribute: 'per' }
|
||||
# {type: 'todo', text: t('defaultTodo4Text'), notes: t('defaultTodoNotes'), checklist: [{completed: false, text: t('defaultTodo4Checklist1') }, {completed: false, text: t('defaultTodo4Checklist2')}, {completed: false, text: t('defaultTodo4Checklist3')}], completed: false, attribute: 'per' }
|
||||
# {type: 'todo', text: t('defaultTodo5Text'), notes: t('defaultTodoNotes'), completed: false, attribute: 'per' }
|
||||
]
|
||||
|
||||
rewards: [
|
||||
{type: 'reward', text: t('defaultReward1Text'), notes: t('defaultReward1Notes'), value: 20 }
|
||||
{type: 'reward', text: t('defaultReward2Text'), notes: t('defaultReward2Notes'), value: 10 }
|
||||
# {type: 'reward', text: t('defaultReward1Text'), notes: t('defaultReward1Notes'), value: 20 }
|
||||
# {type: 'reward', text: t('defaultReward2Text'), notes: t('defaultReward2Notes'), value: 10 }
|
||||
]
|
||||
|
||||
tags: [
|
||||
|
|
|
|||
3
migrations/20150218_interactive_tour.js
Normal file
3
migrations/20150218_interactive_tour.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
//db.users.update({'flags.showTour':{$ne:false}},{$set:{'flags.tour.intro':0}},{multi:1})
|
||||
//db.users.update({'flags.showTour':false},{$set:{'flags.tour.intro':-1}},{multi:1})
|
||||
db.users.update({},{$set:{'flags.tour.intro':-1}},{multi:1})
|
||||
|
|
@ -55,12 +55,11 @@ habitrpg.controller('SettingsCtrl',
|
|||
|
||||
$scope.showTour = function(){
|
||||
User.set({'flags.showTour':true});
|
||||
$location.path('/tasks');
|
||||
$timeout(Guide.initTour);
|
||||
Guide.goto('intro', 0, true);
|
||||
}
|
||||
|
||||
$scope.showClassesTour = function(){
|
||||
Guide.classesTour();
|
||||
Guide.goto('classes', 0, true);
|
||||
}
|
||||
|
||||
$scope.showBailey = function(){
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'ApiUrl', '$timeout', 'Shared',
|
||||
function($scope, $rootScope, $location, User, Notification, $http, ApiUrl, $timeout, Shared) {
|
||||
habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','Notification', '$http', 'ApiUrl', '$timeout', 'Shared', 'Guide',
|
||||
function($scope, $rootScope, $location, User, Notification, $http, ApiUrl, $timeout, Shared, Guide) {
|
||||
$scope.obj = User.user; // used for task-lists
|
||||
$scope.user = User.user;
|
||||
|
||||
|
|
@ -15,6 +15,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
|||
break;
|
||||
case 'todo':
|
||||
$rootScope.playSound('ToDo');
|
||||
Guide.goto('intro', 1);
|
||||
break;
|
||||
default:
|
||||
if (direction === 'down') $rootScope.playSound('Minus_Habit');
|
||||
|
|
@ -46,6 +47,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
|||
}
|
||||
delete listDef.newTask;
|
||||
delete listDef.focus;
|
||||
if (listDef.type=='daily') Guide.goto('intro', 2);
|
||||
};
|
||||
|
||||
$scope.toggleBulk = function(list) {
|
||||
|
|
@ -92,6 +94,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
|||
if (!stayOpen) task._editing = false;
|
||||
if (isSaveAndClose)
|
||||
$("#task-" + task.id).parent().children('.popover').removeClass('in');
|
||||
if (task.type == 'habit') Guide.goto('intro', 3);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -194,6 +197,7 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
|
|||
$scope.buy = function(item) {
|
||||
User.user.ops.buy({params:{key:item.key}});
|
||||
$rootScope.playSound('Reward');
|
||||
Guide.goto('intro', 4);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ habitrpg.controller("UserCtrl", ['$rootScope', '$scope', '$location', 'User', '$
|
|||
User.user.ops.changeClass({query:{class:klass}});
|
||||
$scope.selectedClass = undefined;
|
||||
Shared.updateStore(User.user);
|
||||
$state.go('options.profile.stats');
|
||||
window.setTimeout(Guide.classesTour, 10);
|
||||
Guide.goto('classes', 0,true);
|
||||
}
|
||||
|
||||
$scope.save = function(){
|
||||
|
|
|
|||
|
|
@ -7,214 +7,205 @@
|
|||
angular.module('habitrpg').factory('Guide',
|
||||
['$rootScope', 'User', '$timeout', '$state',
|
||||
function($rootScope, User, $timeout, $state) {
|
||||
/**
|
||||
* Init and show the welcome tour. Note we do it listening to a $rootScope broadcasted 'userLoaded' message,
|
||||
* this because we need to determine whether to show the tour *after* the user has been pulled from the server,
|
||||
* otherwise it's always start off as true, and then get set to false later
|
||||
*/
|
||||
var tourRunning = false;
|
||||
$rootScope.$on('userUpdated', initTour);
|
||||
function initTour(){
|
||||
if (User.user.flags.showTour === false || tourRunning) return;
|
||||
tourRunning = true;
|
||||
var tourSteps = [
|
||||
{
|
||||
orphan:true,
|
||||
title: window.env.t('welcomeHabit'),
|
||||
content: window.env.t('welcomeHabitT1') + " <a href='http://www.kickstarter.com/profile/1823740484' target='_blank'>Justin</a>, " + window.env.t('welcomeHabitT2'),
|
||||
}, {
|
||||
element: ".main-herobox",
|
||||
title: window.env.t('yourAvatar'),
|
||||
content: window.env.t('yourAvatarText'),
|
||||
}, {
|
||||
element: ".main-herobox",
|
||||
title: window.env.t('avatarCustom'),
|
||||
content: window.env.t('avatarCustomText'),
|
||||
}, {
|
||||
element: ".hero-stats",
|
||||
title: window.env.t('hitPoints'),
|
||||
content: window.env.t('hitPointsText'),
|
||||
}, {
|
||||
element: ".hero-stats",
|
||||
title: window.env.t('expPoints'),
|
||||
content: window.env.t('expPointsText'),
|
||||
}, {
|
||||
element: "ul.habits",
|
||||
title: window.env.t('typeGoals'),
|
||||
content: window.env.t('typeGoalsText'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.habits",
|
||||
title: window.env.t('habits'),
|
||||
content: window.env.t('tourHabits'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.dailys",
|
||||
title: window.env.t('dailies'),
|
||||
content: window.env.t('tourDailies'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.todos",
|
||||
title: window.env.t('todos'),
|
||||
content: window.env.t('tourTodos'),
|
||||
placement: "top",
|
||||
}, {
|
||||
element: "ul.main-list.rewards",
|
||||
title: window.env.t('rewards'),
|
||||
content: window.env.t('tourRewards'),
|
||||
placement: "top"
|
||||
}, {
|
||||
element: "ul.habits li:first-child",
|
||||
title: window.env.t('hoverOver'),
|
||||
content: window.env.t('hoverOverText'),
|
||||
placement: "right"
|
||||
}, {
|
||||
orphan:true,
|
||||
title: window.env.t('unlockFeatures'),
|
||||
content: window.env.t('unlockFeaturesT1') + " <a href='http://habitrpg.wikia.com' target='_blank'>" + window.env.t('habitWiki') + "</a> " + window.env.t('unlockFeaturesT2'),
|
||||
placement: "right"
|
||||
}
|
||||
];
|
||||
$('.main-herobox').popover('destroy');
|
||||
var tour = new Tour({
|
||||
backdrop: true,
|
||||
//orphan: true,
|
||||
//keyboard: false,
|
||||
template: '<div class="popover" role="tooltip"> <div class="arrow"></div> <h3 class="popover-title"></h3> <div class="popover-content"></div> <div class="popover-navigation"> <div class="btn-group"> <button class="btn btn-sm btn-default" data-role="prev">« Prev</button> <button class="btn btn-sm btn-default" data-role="next">Next »</button> <button class="btn btn-sm btn-default" data-role="pause-resume" data-pause-text="Pause" data-resume-text="Resume">Pause</button> </div> <button class="btn btn-sm btn-default" data-role="end">' + window.env.t('endTour') + '</button> </div> </div>',
|
||||
onEnd: function(){
|
||||
User.set({'flags.showTour': false});
|
||||
}
|
||||
});
|
||||
_.each(tourSteps, function(step) {
|
||||
|
||||
var chapters = {
|
||||
intro: [
|
||||
[ //0
|
||||
{
|
||||
state: 'tasks',
|
||||
element: ".task-column.todos",
|
||||
content: window.env.t('tourWelcome'),
|
||||
placement: "top"
|
||||
}
|
||||
], [ //1
|
||||
{
|
||||
state: 'tasks',
|
||||
element: '.sticky-wrapper',
|
||||
content: window.env.t('tourExp'),
|
||||
placement: 'bottom'
|
||||
}, {
|
||||
state: 'tasks',
|
||||
element: ".task-column.dailys",
|
||||
content: window.env.t('tourDailies'),
|
||||
placement: "top"
|
||||
}
|
||||
], [ //2
|
||||
{
|
||||
orphan: true,
|
||||
content: window.env.t('tourCron'),
|
||||
placement: 'bottom'
|
||||
}, {
|
||||
state: 'tasks',
|
||||
element: '.meter.health',
|
||||
content: window.env.t('tourHP'),
|
||||
placement: 'bottom'
|
||||
}, {
|
||||
state: 'tasks',
|
||||
element: ".task-column.habits",
|
||||
content: window.env.t('tourHabits'),
|
||||
placement: "right"
|
||||
}
|
||||
], [ //3
|
||||
{
|
||||
state: 'tasks',
|
||||
element: ".hero-stats",
|
||||
content: window.env.t('tourStats')
|
||||
}, {
|
||||
state: 'tasks',
|
||||
element: ".task-column.rewards",
|
||||
content: window.env.t('tourGP'),
|
||||
placement: 'left'
|
||||
}
|
||||
], [ //4
|
||||
{
|
||||
state: 'tasks',
|
||||
element: '.main-herobox',
|
||||
content: window.env.t('tourAvatar'),
|
||||
placement: 'bottom'
|
||||
}
|
||||
], [ //5
|
||||
{
|
||||
state: 'options.profile.avatar',
|
||||
orphan: true,
|
||||
content: window.env.t('tourScrollDown')
|
||||
}, {
|
||||
element: "ul.toolbar-nav",
|
||||
backdrop:false,
|
||||
content: window.env.t('tourMuchMore'),
|
||||
placement: "bottom",
|
||||
final: true,
|
||||
//onHidden: function(){
|
||||
// $rootScope.$watch('user.flags.customizationsNotification', _.partial(goto, 'intro', 4));
|
||||
//}
|
||||
}
|
||||
]
|
||||
],
|
||||
classes: [
|
||||
[
|
||||
{
|
||||
state: 'options.inventory.equipment',
|
||||
element: '.equipment-tab',
|
||||
title: window.env.t('classGear'),
|
||||
content: window.env.t('classGearText', {klass: User.user.stats.class})
|
||||
}, {
|
||||
state: 'options.profile.stats',
|
||||
element: ".allocate-stats",
|
||||
title: window.env.t('stats'),
|
||||
content: window.env.t('classStats')
|
||||
}, {
|
||||
state: 'options.profile.stats',
|
||||
element: ".auto-allocate",
|
||||
title: window.env.t('autoAllocate'),
|
||||
placement: 'left',
|
||||
content: window.env.t('autoAllocateText')
|
||||
}, {
|
||||
element: ".meter.mana",
|
||||
title: window.env.t('spells'),
|
||||
content: window.env.t('spellsText') + " <a target='_blank' href='http://habitrpg.wikia.com/wiki/Todos'>" + window.env.t('toDo') + "</a>."
|
||||
}, {
|
||||
orphan: true,
|
||||
title: window.env.t('readMore'),
|
||||
content: window.env.t('moreClass') + " <a href='http://habitrpg.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>.",
|
||||
final: true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
_.each(chapters, function(chapter, k){
|
||||
_(chapter).flatten().each(function(step) {
|
||||
step.content = "<div><div class='" + (env.worldDmg.guide ? "npc_justin_broken" : "npc_justin") + " float-left'></div>" + step.content + "</div>";
|
||||
$(step.element).popover('destroy'); // destroy existing hover popovers so we can add our own
|
||||
step.onShow = function(){
|
||||
// Since all the steps are currently on the tasks page, ensure we go back there for each step in case they
|
||||
// clicked elsewhere during the tour. FIXME: $state.go() returns a promise, necessary for async tour steps;
|
||||
// however, that's not working here - have to use timeout instead :/
|
||||
if (!$state.is('tasks')) return $timeout(function(){$state.go('tasks');}, 0)
|
||||
// step.path doesn't work in Angular do to async ui-router. Our custom solution:
|
||||
if (step.state && !$state.is(step.state)) {
|
||||
// $state.go() returns a promise, necessary for async tour steps; however, that's not working here - have to use timeout instead :/
|
||||
$state.go(step.state);
|
||||
return $timeout(function(){});
|
||||
}
|
||||
}
|
||||
step.html = true;
|
||||
tour.addStep(step);
|
||||
step.onHide = function(){
|
||||
if (step.final) { // -1 indicates complete
|
||||
var ups={};ups['flags.tour.'+k] = -1;
|
||||
User.set(ups);
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
var tour = {};
|
||||
_.each(chapters, function(v,k){
|
||||
tour[k] = new Tour({
|
||||
backdrop: true,
|
||||
template: function(i,step){
|
||||
return '<div class="popover" role="tooltip"> ' +
|
||||
'<div class="arrow"></div> ' +
|
||||
'<h3 class="popover-title"></h3> ' +
|
||||
'<div class="popover-content"></div> ' +
|
||||
'<div class="popover-navigation"> ' +
|
||||
//'<button class="btn btn-sm btn-default" data-role="end" style="float:none;">' + (step.final ? 'Finish Tour' : 'Hide') + '</button>'+
|
||||
(step.final ? '<button class="btn btn-sm btn-default" data-role="end" style="float:none;">Finish Tour</button>' : '')+
|
||||
'<div class="btn-group"> ' +
|
||||
'<button class="btn btn-sm btn-default" data-role="prev">« Prev</button> ' +
|
||||
'<button class="btn btn-sm btn-default" data-role="next">Next »</button> ' +
|
||||
'<button class="btn btn-sm btn-default" data-role="pause-resume" data-pause-text="Pause" data-resume-text="Resume">Pause</button> ' +
|
||||
'</div> ' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
},
|
||||
storage: false,
|
||||
//onEnd: function(){
|
||||
// User.set({'flags.showTour': false});
|
||||
//}
|
||||
});
|
||||
tour.restart(); // Tour doesn't quite mesh with our handling of flags.showTour, just restart it on page load
|
||||
//tour.start(true);
|
||||
};
|
||||
});
|
||||
|
||||
var alreadyShown = function(before, after) {
|
||||
return !(!before && after === true);
|
||||
};
|
||||
|
||||
var showPopover = function(selector, title, html, placement) {
|
||||
if (!placement) placement = 'bottom';
|
||||
$(selector).popover('destroy');
|
||||
var button = "<button class='btn btn-sm btn-default' onClick=\"$('" + selector + "').popover('hide');return false;\">" + window.env.t('close') + "</button>";
|
||||
if (env.worldDmg.guide) {
|
||||
html = "<div><div class='npc_justin_broken float-left'></div>" + html + '<br/>' + button + '</div>';
|
||||
var goto = function(chapter, page, force) {
|
||||
var curr = User.user.flags.tour[chapter];
|
||||
if ((page != curr+1 || curr > page) && !force) return;
|
||||
var updates = {};updates['flags.tour.'+chapter] = page;
|
||||
User.set(updates);
|
||||
var chap = tour[chapter], opts = chap._options;
|
||||
opts.steps = [];
|
||||
_.times(page, function(p){
|
||||
opts.steps = opts.steps.concat(chapters[chapter][p]);
|
||||
})
|
||||
var end = opts.steps.length;
|
||||
opts.steps = opts.steps.concat(chapters[chapter][page]);
|
||||
chap._removeState('end');
|
||||
if (chap._inited) {
|
||||
chap.goTo(end);
|
||||
} else {
|
||||
html = "<div><div class='npc_justin float-left'></div>" + html + '<br/>' + button + '</div>';
|
||||
chap.setCurrentStep(end);
|
||||
chap.start();
|
||||
}
|
||||
$(selector).popover({
|
||||
title: title,
|
||||
placement: placement,
|
||||
trigger: 'manual',
|
||||
html: true,
|
||||
content: html
|
||||
}).popover('show');
|
||||
};
|
||||
}
|
||||
|
||||
$rootScope.$watch('user.flags.customizationsNotification', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
showPopover('.main-herobox', window.env.t('customAvatar'), window.env.t('customAvatarText'), 'bottom');
|
||||
});
|
||||
//Init and show the welcome tour (only after user is pulled from server & wrapped).
|
||||
var watcher = $rootScope.$watch('User.user.ops.update', function(updateFn){
|
||||
if (!updateFn) return; // only run after user has been wrapped
|
||||
watcher(); // deregister watcher
|
||||
if (window.env.IS_MOBILE) return; // Don't show tour immediately on mobile devices
|
||||
goto('intro', User.user.flags.tour.intro, true);
|
||||
|
||||
$rootScope.$watch('user.flags.itemsEnabled', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
var html = window.env.t('storeUnlockedText');
|
||||
showPopover('div.rewards', window.env.t('storeUnlocked'), html, 'left');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.flags.partyEnabled', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
var html = window.env.t('partySysText');
|
||||
showPopover('.user-menu', window.env.t('partySys'), html, 'bottom');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.flags.dropsEnabled', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
var eggs = User.user.items.eggs || {};
|
||||
if (!eggs) {
|
||||
eggs['Wolf'] = 1; // This is also set on the server
|
||||
}
|
||||
$rootScope.openModal('dropsEnabled');
|
||||
});
|
||||
|
||||
$rootScope.$watch('user.flags.rebirthEnabled', function(after, before) {
|
||||
var alreadyShown = function(before, after) { return !(!before && after === true) };
|
||||
//$rootScope.$watch('user.flags.dropsEnabled', _.flow(alreadyShown, function(already) { //FIXME requires lodash@~3.2.0
|
||||
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){
|
||||
if (toState.name == 'options.profile.avatar') goto('intro', 5);
|
||||
})
|
||||
$rootScope.$watch('user.flags.dropsEnabled', function(after, before) {
|
||||
if (alreadyShown(before,after)) return;
|
||||
var eggs = User.user.items.eggs || {};
|
||||
if (!eggs) eggs['Wolf'] = 1; // This is also set on the server
|
||||
$rootScope.openModal('dropsEnabled');
|
||||
});
|
||||
$rootScope.$watch('user.flags.rebirthEnabled', function(after, before) {
|
||||
if (alreadyShown(before, after)) return;
|
||||
$rootScope.openModal('rebirthEnabled');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Classes Tour
|
||||
*/
|
||||
function classesTour(){
|
||||
|
||||
// TODO notice my hack-job `onShow: _.once()` functions. Without these, the syncronous path redirects won't properly handle showing tour
|
||||
var tourSteps = [
|
||||
{
|
||||
path: '/#/options/inventory/equipment',
|
||||
onShow: _.once(function(tour){
|
||||
$timeout(function(){tour.goTo(0)});
|
||||
}),
|
||||
element: '.equipment-tab',
|
||||
title: window.env.t('classGear'),
|
||||
content: window.env.t('classGearText', {klass: User.user.stats.class})
|
||||
},
|
||||
{
|
||||
path: '/#/options/profile/stats',
|
||||
onShow: _.once(function(tour){
|
||||
$timeout(function(){tour.goTo(1)});
|
||||
}),
|
||||
element: ".allocate-stats",
|
||||
title: window.env.t('stats'),
|
||||
content: window.env.t('classStats'),
|
||||
}, {
|
||||
element: ".auto-allocate",
|
||||
title: window.env.t('autoAllocate'),
|
||||
placement: 'left',
|
||||
content: window.env.t('autoAllocateText'),
|
||||
}, {
|
||||
element: ".meter.mana",
|
||||
title: window.env.t('spells'),
|
||||
content: window.env.t('spellsText') + " <a target='_blank' href='http://habitrpg.wikia.com/wiki/Todos'>" + window.env.t('toDo') + "</a>."
|
||||
}, {
|
||||
orphan: true,
|
||||
title: window.env.t('readMore'),
|
||||
content: window.env.t('moreClass') + " <a href='http://habitrpg.wikia.com/wiki/Class_System' target='_blank'>Wikia</a>."
|
||||
}
|
||||
];
|
||||
_.each(tourSteps, function(step){
|
||||
if (env.worldDmg.guide) {
|
||||
step.content = "<div><div class='npc_justin_broken float-left'></div>" + step.content + "</div>";
|
||||
} else {
|
||||
step.content = "<div><div class='npc_justin float-left'></div>" + step.content + "</div>";
|
||||
}
|
||||
});
|
||||
$('.allocate-stats').popover('destroy');
|
||||
var tour = new Tour({
|
||||
// onEnd: function(){
|
||||
// User.set({'flags.showTour': false});
|
||||
// }
|
||||
});
|
||||
tourSteps.forEach(function(step) {
|
||||
tour.addStep(_.defaults(step, {html: true}));
|
||||
});
|
||||
tour.restart(); // Tour doesn't quite mesh with our handling of flags.showTour, just restart it on page load
|
||||
//tour.start(true);
|
||||
};
|
||||
|
||||
return {
|
||||
initTour: initTour,
|
||||
classesTour: classesTour
|
||||
goto: goto
|
||||
};
|
||||
|
||||
}]);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ angular.module("habitrpg").factory("Notification",
|
|||
function notify(html, type, icon) {
|
||||
var notice = $.pnotify({
|
||||
type: type || 'warning', //('info', 'text', 'warning', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp', 'crit')
|
||||
text: html,
|
||||
text: html,
|
||||
opacity: 1,
|
||||
addclass: 'alert-' + type,
|
||||
delay: 7000,
|
||||
|
|
|
|||
|
|
@ -119,6 +119,10 @@ var UserSchema = new Schema({
|
|||
flags: {
|
||||
customizationsNotification: {type: Boolean, 'default': false},
|
||||
showTour: {type: Boolean, 'default': true},
|
||||
tour: {
|
||||
intro: {type: Number, 'default': 0},
|
||||
classes: {type: Number, 'default': 0}
|
||||
},
|
||||
dropsEnabled: {type: Boolean, 'default': false},
|
||||
itemsEnabled: {type: Boolean, 'default': false},
|
||||
newStuff: {type: Boolean, 'default': false},
|
||||
|
|
@ -150,12 +154,12 @@ var UserSchema = new Schema({
|
|||
gear: {
|
||||
owned: _.transform(shared.content.gear.flat, function(m,v,k){
|
||||
m[v.key] = {type: Boolean};
|
||||
if (v.key.match(/[weapon|armor|head|shield]_warrior_0/))
|
||||
if (v.key.match(/[armor|head|shield]_warrior_0/))
|
||||
m[v.key]['default'] = true;
|
||||
}),
|
||||
|
||||
equipped: {
|
||||
weapon: {type: String, 'default': 'weapon_warrior_0'},
|
||||
weapon: String,
|
||||
armor: {type: String, 'default': 'armor_base_0'},
|
||||
head: {type: String, 'default': 'head_base_0'},
|
||||
shield: {type: String, 'default': 'shield_base_0'},
|
||||
|
|
@ -165,7 +169,7 @@ var UserSchema = new Schema({
|
|||
body: String
|
||||
},
|
||||
costume: {
|
||||
weapon: {type: String, 'default': 'weapon_base_0'},
|
||||
weapon: String,
|
||||
armor: {type: String, 'default': 'armor_base_0'},
|
||||
head: {type: String, 'default': 'head_base_0'},
|
||||
shield: {type: String, 'default': 'shield_base_0'},
|
||||
|
|
@ -173,7 +177,7 @@ var UserSchema = new Schema({
|
|||
headAccessory: String,
|
||||
eyewear: String,
|
||||
body: String
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
special:{
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ nav.toolbar(ng-controller='AuthCtrl', ng-class='{active: isToolbarHidden}')
|
|||
a(target="_blank" href='http://habitrpg.wikia.com/wiki/Contributing_to_HabitRPG')=env.t('contributeToHRPG')
|
||||
li
|
||||
a(target="_blank" href='http://habitrpg.wikia.com/wiki/')=env.t('overview')
|
||||
li(ng-controller='SettingsCtrl')
|
||||
//-li(ng-controller='SettingsCtrl')
|
||||
a(ng-click='showTour()', popover-placement='right', popover-trigger='mouseenter', popover=env.t('restartTour'))= env.t('showTour')
|
||||
ul.toolbar-subscribe(ng-if='!user.purchased.plan.customerId')
|
||||
li.toolbar-subscribe-button
|
||||
|
|
|
|||
|
|
@ -78,12 +78,8 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
|
|||
|
||||
+taskColumnTabs('top')
|
||||
|
||||
// Actual List
|
||||
ul(class='{{list.type}}s main-list', ng-show='obj[list.type + "s"].length > 0', hrpg-sort-tasks)
|
||||
include ./task
|
||||
|
||||
// Static Rewards
|
||||
ul.items.rewards(ng-if='main && list.type=="reward" && user.flags.itemsEnabled')
|
||||
ul.items.rewards(ng-if='main && list.type=="reward"')
|
||||
li.task.reward-item(ng-repeat='item in itemStore',popover-trigger='mouseenter', popover-placement='top', popover='{{item.notes()}}')
|
||||
// right-hand side control buttons
|
||||
.task-meta-controls
|
||||
|
|
@ -124,6 +120,10 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
|
|||
+specialSpell('salt','snowball')
|
||||
+specialSpell('opaquePotion','spookDust')
|
||||
|
||||
// Actual List
|
||||
ul(class='{{list.type}}s main-list', ng-show='obj[list.type + "s"].length > 0', hrpg-sort-tasks)
|
||||
include ./task
|
||||
|
||||
// Spells
|
||||
ul.items(ng-if='main && list.type=="reward" && user.stats.class && !user.preferences.disableClasses')
|
||||
li.task.reward-item(ng-repeat='(k,skill) in Content.spells[user.stats.class]', ng-if='user.stats.lvl >= skill.lvl',popover-trigger='mouseenter', popover-placement='top', popover='{{skill.notes()}}')
|
||||
|
|
@ -143,7 +143,7 @@ script(id='templates/habitrpg-tasks.html', type="text/ng-template")
|
|||
br
|
||||
|
||||
// Ads
|
||||
div(ng-if='::main && !user.purchased.ads && !user.purchased.plan.customerId && list.type!="reward"')
|
||||
div(ng-if='::main && !user.purchased.ads && !user.purchased.plan.customerId && list.type!="reward" && user.stats.lvl>1')
|
||||
span.pull-right
|
||||
a(ui-sref='options.settings.subscription', popover=env.t('removeAds'), popover-trigger='mouseenter')
|
||||
span.glyphicon.glyphicon-remove
|
||||
|
|
|
|||
Loading…
Reference in a new issue