mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-05-24 06:35:37 +00:00
Merge branch 'develop' into release
This commit is contained in:
commit
569fb11db8
8 changed files with 70 additions and 29 deletions
|
|
@ -138,12 +138,21 @@ export default {
|
|||
// @TODO split up this file, it's too big
|
||||
// Set up Error interceptors
|
||||
axios.interceptors.response.use((response) => {
|
||||
if (this.user) {
|
||||
if (this.user && response.data && response.data.notifications) {
|
||||
this.$set(this.user, 'notifications', response.data.notifications);
|
||||
}
|
||||
return response;
|
||||
}, (error) => {
|
||||
if (error.response.status >= 400) {
|
||||
// Don't show errors from getting user details. These users have delete their account,
|
||||
// but their chat message still exists.
|
||||
let configExists = Boolean(error.response) && Boolean(error.response.config);
|
||||
if (configExists && error.response.config.method === 'get' && error.response.config.url.indexOf('/api/v3/members/') !== -1) {
|
||||
// @TODO: We resolve the promise because we need our caching to cache this user as tried
|
||||
// Chat paging should help this, but maybe we can also find another solution..
|
||||
return Promise.resolve(error);
|
||||
}
|
||||
|
||||
this.$store.state.notificationStore.push({
|
||||
title: 'Habitica',
|
||||
text: error.response.data.message,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
li
|
||||
a(href='/apidoc', target='_blank') {{ $t('APIv3') }}
|
||||
li
|
||||
a(href='http://data.habitrpg.com/?uuid=', target='_blank') {{ $t('dataDisplayTool') }}
|
||||
a(href='https://oldgods.net/habitrpg/habitrpg_user_data_display.html', target='_blank') {{ $t('dataDisplayTool') }}
|
||||
li
|
||||
a(href='http://habitica.wikia.com/wiki/Guidance_for_Blacksmiths', target='_blank') {{ $t('guidanceForBlacksmiths') }}
|
||||
li
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@
|
|||
copy-as-todo-modal(:copying-message='copyingMessage', :group-name='groupName', :group-id='groupId')
|
||||
report-flag-modal
|
||||
|
||||
div(v-for="(msg, index) in chat", v-if='chat && canViewFlag(msg)')
|
||||
div(v-for="(msg, index) in messages", v-if='chat && canViewFlag(msg)')
|
||||
// @TODO: is there a different way to do these conditionals? This creates an infinite loop
|
||||
//.hr(v-if='displayDivider(msg)')
|
||||
.hr-middle(v-once) {{ msg.timestamp }}
|
||||
.row(v-if='user._id !== msg.uuid')
|
||||
div(:class='inbox ? "col-4" : "col-2"')
|
||||
avatar(
|
||||
v-if='cachedProfileData[msg.uuid]',
|
||||
v-if='cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected',
|
||||
:member="cachedProfileData[msg.uuid]",
|
||||
:avatarOnly="true",
|
||||
:hideClassBadge='true',
|
||||
|
|
@ -36,13 +36,15 @@
|
|||
.svg-icon(v-html="icons.like")
|
||||
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
|
||||
span(v-if='msg.likes[user._id]') {{ $t('liked') }}
|
||||
span.action( @click='copyAsTodo(msg)')
|
||||
span.action(v-if='!inbox', @click='copyAsTodo(msg)')
|
||||
.svg-icon(v-html="icons.copy")
|
||||
| {{$t('copyAsTodo')}}
|
||||
span.action(v-if='user.contributor.admin || (msg.uuid !== user._id && user.flags.communityGuidelinesAccepted)', @click='report(msg)')
|
||||
// @TODO make copyAsTodo work in the inbox
|
||||
span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted', @click='report(msg)')
|
||||
.svg-icon(v-html="icons.report")
|
||||
| {{$t('report')}}
|
||||
span.action(v-if='msg.uuid === user._id || inbox', @click='remove(msg, index)')
|
||||
// @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys
|
||||
span.action(v-if='msg.uuid === user._id || inbox || user.contributor.admin', @click='remove(msg, index)')
|
||||
.svg-icon(v-html="icons.delete")
|
||||
| {{$t('delete')}}
|
||||
span.action.float-right.liked(v-if='likeCount(msg) > 0')
|
||||
|
|
@ -70,12 +72,15 @@
|
|||
.svg-icon(v-html="icons.like")
|
||||
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
|
||||
span(v-if='msg.likes[user._id]') {{ $t('liked') }}
|
||||
span.action( @click='copyAsTodo(msg)')
|
||||
span.action(v-if='!inbox', @click='copyAsTodo(msg)')
|
||||
.svg-icon(v-html="icons.copy")
|
||||
| {{$t('copyAsTodo')}}
|
||||
// @TODO make copyAsTodo work in the inbox
|
||||
span.action(v-if='user.flags.communityGuidelinesAccepted', @click='report(msg)')
|
||||
span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted', @click='report(msg)')
|
||||
.svg-icon(v-html="icons.report")
|
||||
| {{$t('report')}}
|
||||
// @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys
|
||||
span.action(v-if='msg.uuid === user._id', @click='remove(msg, index)')
|
||||
.svg-icon(v-html="icons.delete")
|
||||
| {{$t('delete')}}
|
||||
|
|
@ -84,7 +89,7 @@
|
|||
| + {{ likeCount(msg) }}
|
||||
div(:class='inbox ? "col-4" : "col-2"')
|
||||
avatar(
|
||||
v-if='cachedProfileData[msg.uuid]',
|
||||
v-if='cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected',
|
||||
:member="cachedProfileData[msg.uuid]",
|
||||
:avatarOnly="true",
|
||||
:hideClassBadge='true',
|
||||
|
|
@ -238,7 +243,7 @@ import axios from 'axios';
|
|||
import moment from 'moment';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import throttle from 'lodash/throttle';
|
||||
import debounce from 'lodash/debounce';
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
import Avatar from '../avatar';
|
||||
import styleHelper from 'client/mixins/styleHelper';
|
||||
|
|
@ -277,12 +282,10 @@ export default {
|
|||
this.loadProfileCache();
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('scroll', throttle(() => {
|
||||
this.loadProfileCache(window.scrollY / 1000);
|
||||
}, 1000));
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
destroyed () {
|
||||
// window.removeEventListener('scroll', this.handleScroll);
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
|
@ -308,6 +311,7 @@ export default {
|
|||
cachedProfileData: {},
|
||||
currentProfileLoadedCount: 0,
|
||||
currentProfileLoadedEnd: 10,
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
|
|
@ -321,17 +325,22 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
// @TODO: We need a different lazy load mechnism.
|
||||
// But honestly, adding a paging route to chat would solve this
|
||||
messages () {
|
||||
return this.chat;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
messages () {
|
||||
// @TODO: MAybe we should watch insert and remove?
|
||||
messages (oldValue, newValue) {
|
||||
if (newValue.length === oldValue.length) return;
|
||||
this.loadProfileCache();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleScroll () {
|
||||
this.loadProfileCache(window.scrollY / 1000);
|
||||
},
|
||||
isUserMentioned (message) {
|
||||
let user = this.user;
|
||||
|
||||
|
|
@ -358,7 +367,10 @@ export default {
|
|||
if (!message.flagCount || message.flagCount < 2) return true;
|
||||
return this.user.contributor.admin;
|
||||
},
|
||||
async loadProfileCache (screenPosition) {
|
||||
loadProfileCache: debounce(function loadProfileCache (screenPosition) {
|
||||
this._loadProfileCache(screenPosition);
|
||||
}, 1000),
|
||||
async _loadProfileCache (screenPosition) {
|
||||
let promises = [];
|
||||
|
||||
// @TODO: write an explination
|
||||
|
|
@ -368,11 +380,10 @@ export default {
|
|||
return;
|
||||
}
|
||||
|
||||
// @TODO: Not sure we need this hash
|
||||
let aboutToCache = {};
|
||||
this.messages.forEach(message => {
|
||||
let uuid = message.uuid;
|
||||
if (uuid && !this.cachedProfileData[uuid] && !aboutToCache[uuid]) {
|
||||
if (Boolean(uuid) && !this.cachedProfileData[uuid] && !aboutToCache[uuid]) {
|
||||
if (uuid === 'system' || this.currentProfileLoadedCount === this.currentProfileLoadedEnd) return;
|
||||
aboutToCache[uuid] = {};
|
||||
promises.push(axios.get(`/api/v3/members/${uuid}`));
|
||||
|
|
@ -382,9 +393,21 @@ export default {
|
|||
|
||||
let results = await Promise.all(promises);
|
||||
results.forEach(result => {
|
||||
// We could not load the user. Maybe they were deleted. So, let's cache empty so we don't try again
|
||||
if (!result || !result.data || result.status >= 400) {
|
||||
return;
|
||||
}
|
||||
|
||||
let userData = result.data.data;
|
||||
this.$set(this.cachedProfileData, userData._id, userData);
|
||||
});
|
||||
|
||||
// Merge in any attempts that were rejected so we don't attempt again
|
||||
for (let uuid in aboutToCache) {
|
||||
if (!this.cachedProfileData[uuid]) {
|
||||
this.$set(this.cachedProfileData, uuid, {rejected: true});
|
||||
}
|
||||
}
|
||||
},
|
||||
displayDivider (message) {
|
||||
if (this.currentDayDividerDisplay !== moment(message.timestamp).day()) {
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@
|
|||
</style>
|
||||
|
||||
<script>
|
||||
import debounce from 'lodash/debounce';
|
||||
import extend from 'lodash/extend';
|
||||
import groupUtilities from 'client/mixins/groupsUtilities';
|
||||
import styleHelper from 'client/mixins/styleHelper';
|
||||
|
|
@ -655,7 +656,10 @@ export default {
|
|||
};
|
||||
document.body.removeChild(div);
|
||||
},
|
||||
updateCarretPosition (eventUpdate) {
|
||||
updateCarretPosition: debounce(function updateCarretPosition (eventUpdate) {
|
||||
this._updateCarretPosition(eventUpdate);
|
||||
}, 250),
|
||||
_updateCarretPosition (eventUpdate) {
|
||||
if (eventUpdate.metaKey && eventUpdate.keyCode === 13) {
|
||||
this.sendMessage();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -350,6 +350,7 @@
|
|||
</style>
|
||||
|
||||
<script>
|
||||
import debounce from 'lodash/debounce';
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
import { TAVERN_ID } from '../../../common/script/constants';
|
||||
|
|
@ -527,7 +528,10 @@ export default {
|
|||
};
|
||||
document.body.removeChild(div);
|
||||
},
|
||||
updateCarretPosition (eventUpdate) {
|
||||
updateCarretPosition: debounce(function updateCarretPosition (eventUpdate) {
|
||||
this._updateCarretPosition(eventUpdate);
|
||||
}, 250),
|
||||
_updateCarretPosition (eventUpdate) {
|
||||
if (eventUpdate.metaKey && eventUpdate.keyCode === 13) {
|
||||
this.sendMessage();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@
|
|||
h6(v-once) {{ $t('class') + ': ' }}
|
||||
// @TODO: what is classText
|
||||
span(v-if='classText') {{ classText }}
|
||||
button.btn.btn-danger.btn-xs(@click='changeClass(null)', v-once) {{ $t('changeClass') }}
|
||||
small.cost 3
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
button.btn.btn-danger.btn-xs(@click='changeClassForUser(true)', v-once) {{ $t('changeClass') }}
|
||||
small.cost 3 {{ $t('gems') }}
|
||||
// @TODO add icon span.Pet_Currency_Gem1x.inline-gems
|
||||
hr
|
||||
|
||||
div
|
||||
|
|
@ -82,7 +82,7 @@
|
|||
|
||||
button.btn.btn-primary(@click='showBailey()', popover-trigger='mouseenter', popover-placement='right', :popover="$t('showBaileyPop')") {{ $t('showBailey') }}
|
||||
button.btn.btn-primary(@click='openRestoreModal()', popover-trigger='mouseenter', popover-placement='right', :popover="$t('fixValPop')") {{ $t('fixVal') }}
|
||||
button.btn.btn-primary(v-if='user.preferences.disableClasses == true', @click='changeClass({})',
|
||||
button.btn.btn-primary(v-if='user.preferences.disableClasses == true', @click='changeClassForUser(false)',
|
||||
popover-trigger='mouseenter', popover-placement='right', :popover="$t('enableClassPop')") {{ $t('enableClass') }}
|
||||
|
||||
hr
|
||||
|
|
@ -378,8 +378,8 @@ export default {
|
|||
|
||||
this.$router.go('/tasks');
|
||||
},
|
||||
async changeClass () {
|
||||
if (!confirm('Are you sure you want to change your class for 3 gems?')) return;
|
||||
async changeClassForUser (confirmationNeeded) {
|
||||
if (confirmationNeeded && !confirm(this.$t('changeClassConfirmCost'))) return;
|
||||
try {
|
||||
changeClass(this.user);
|
||||
await axios.post('/api/v3/user/change-class');
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ div
|
|||
.profile-actions
|
||||
button.btn.btn-secondary(@click='sendMessage()')
|
||||
.svg-icon.message-icon(v-html="icons.message")
|
||||
button.btn.btn-secondary(v-if='userLoggedIn.inbox.blocks.indexOf(user._id) === -1', :tooltip="$t('unblock')",
|
||||
button.btn.btn-secondary(v-if='user._id !== this.userLoggedIn._id && userLoggedIn.inbox.blocks.indexOf(user._id) === -1', :tooltip="$t('unblock')",
|
||||
@click="blockUser()", tooltip-placement='right')
|
||||
span.glyphicon.glyphicon-plus
|
||||
| {{$t('block')}}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@
|
|||
"mystery": "Mystery",
|
||||
"changeClass": "Change Class, Refund Attribute Points",
|
||||
"lvl10ChangeClass": "To change class you must be at least level 10.",
|
||||
"changeClassConfirmCost": "Are you sure you want to change your class for 3 Gems?",
|
||||
"invalidClass":"Invalid class. Please specify 'warrior', 'rogue', 'wizard', or 'healer'.",
|
||||
"levelPopover": "Each level earns you one point to assign to an attribute of your choice. You can do so manually, or let the game decide for you using one of the Automatic Allocation options.",
|
||||
"unallocated": "Unallocated Attribute Points",
|
||||
|
|
@ -158,7 +159,7 @@
|
|||
"respawn": "Respawn!",
|
||||
"youDied": "You Died!",
|
||||
"dieText": "You've lost a Level, all your Gold, and a random piece of Equipment. Arise, Habiteer, and try again! Curb those negative Habits, be vigilant in completion of Dailies, and hold death at arm's length with a Health Potion if you falter!",
|
||||
"sureReset": "Are you sure? This will reset your character's class and allocated points (you'll get them all back to re-allocate), and costs 3 gems.",
|
||||
"sureReset": "Are you sure? This will reset your character's class and allocated points (you'll get them all back to re-allocate), and costs 3 Gems.",
|
||||
"purchaseFor": "Purchase for <%= cost %> Gems?",
|
||||
"notEnoughMana": "Not enough mana.",
|
||||
"invalidTarget": "You can't cast a skill on that.",
|
||||
|
|
|
|||
Loading…
Reference in a new issue