mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 15:17:25 +01:00
Fix difficult to edit checklists in Firefox (#9525)
* Change checklist item hover from move to text * Add vue draggable * Add vue draggable * Replace sortablejs directive with Vue Draggable component * Indent draggable properties
This commit is contained in:
@@ -122,6 +122,7 @@
|
|||||||
"vue-router": "^3.0.0",
|
"vue-router": "^3.0.0",
|
||||||
"vue-style-loader": "^3.0.0",
|
"vue-style-loader": "^3.0.0",
|
||||||
"vue-template-compiler": "^2.5.2",
|
"vue-template-compiler": "^2.5.2",
|
||||||
|
"vuedraggable": "^2.15.0",
|
||||||
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker#825a866b6a9c52dd8c588a3e8b900880875ce914",
|
"vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker#825a866b6a9c52dd8c588a3e8b900880875ce914",
|
||||||
"webpack": "^2.2.1",
|
"webpack": "^2.2.1",
|
||||||
"webpack-merge": "^4.0.0",
|
"webpack-merge": "^4.0.0",
|
||||||
|
|||||||
@@ -34,11 +34,10 @@
|
|||||||
.svg-icon(v-html="icons[type]", :class="`icon-${type}`", v-once)
|
.svg-icon(v-html="icons[type]", :class="`icon-${type}`", v-once)
|
||||||
h3(v-once) {{$t('theseAreYourTasks', {taskType: $t(types[type].label)})}}
|
h3(v-once) {{$t('theseAreYourTasks', {taskType: $t(types[type].label)})}}
|
||||||
.small-text {{$t(`${type}sDesc`)}}
|
.small-text {{$t(`${type}sDesc`)}}
|
||||||
.sortable-tasks(
|
draggable(
|
||||||
ref="tasksList",
|
ref="tasksList",
|
||||||
v-sortable='activeFilters[type].label !== "scheduled"',
|
@update='sorted',
|
||||||
@onsort='sorted',
|
:options='{disabled: activeFilters[type].label === "scheduled"}',
|
||||||
data-sortableId
|
|
||||||
)
|
)
|
||||||
task(
|
task(
|
||||||
v-for="task in taskList",
|
v-for="task in taskList",
|
||||||
@@ -234,7 +233,6 @@
|
|||||||
import Task from './task';
|
import Task from './task';
|
||||||
import sortBy from 'lodash/sortBy';
|
import sortBy from 'lodash/sortBy';
|
||||||
import throttle from 'lodash/throttle';
|
import throttle from 'lodash/throttle';
|
||||||
import sortable from 'client/directives/sortable.directive';
|
|
||||||
import buyMixin from 'client/mixins/buy';
|
import buyMixin from 'client/mixins/buy';
|
||||||
import { mapState, mapActions } from 'client/libs/store';
|
import { mapState, mapActions } from 'client/libs/store';
|
||||||
import shopItem from '../shops/shopItem';
|
import shopItem from '../shops/shopItem';
|
||||||
@@ -251,6 +249,7 @@ import habitIcon from 'assets/svg/habit.svg';
|
|||||||
import dailyIcon from 'assets/svg/daily.svg';
|
import dailyIcon from 'assets/svg/daily.svg';
|
||||||
import todoIcon from 'assets/svg/todo.svg';
|
import todoIcon from 'assets/svg/todo.svg';
|
||||||
import rewardIcon from 'assets/svg/reward.svg';
|
import rewardIcon from 'assets/svg/reward.svg';
|
||||||
|
import draggable from 'vuedraggable';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [buyMixin, notifications],
|
mixins: [buyMixin, notifications],
|
||||||
@@ -258,9 +257,7 @@ export default {
|
|||||||
Task,
|
Task,
|
||||||
BuyQuestModal,
|
BuyQuestModal,
|
||||||
shopItem,
|
shopItem,
|
||||||
},
|
draggable,
|
||||||
directives: {
|
|
||||||
sortable,
|
|
||||||
},
|
},
|
||||||
props: ['type', 'isUser', 'searchText', 'selectedTags', 'taskListOverride', 'group'], // @TODO: maybe we should store the group on state?
|
props: ['type', 'isUser', 'searchText', 'selectedTags', 'taskListOverride', 'group'], // @TODO: maybe we should store the group on state?
|
||||||
data () {
|
data () {
|
||||||
|
|||||||
@@ -26,7 +26,11 @@
|
|||||||
.option(v-if="checklistEnabled")
|
.option(v-if="checklistEnabled")
|
||||||
label(v-once) {{ $t('checklist') }}
|
label(v-once) {{ $t('checklist') }}
|
||||||
br
|
br
|
||||||
div(v-sortable='true', @onsort='sortedChecklist')
|
draggable(
|
||||||
|
v-model="checklist",
|
||||||
|
:options="{handle: '.grippy', filter: '.task-dropdown'}",
|
||||||
|
@update="sortedChecklist"
|
||||||
|
)
|
||||||
.inline-edit-input-group.checklist-group.input-group(v-for="(item, $index) in checklist")
|
.inline-edit-input-group.checklist-group.input-group(v-for="(item, $index) in checklist")
|
||||||
span.grippy
|
span.grippy
|
||||||
input.inline-edit-input.checklist-item.form-control(type="text", v-model="item.text")
|
input.inline-edit-input.checklist-item.form-control(type="text", v-model="item.text")
|
||||||
@@ -466,6 +470,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
cursor: text;
|
||||||
.destroy-icon {
|
.destroy-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: $gray-200;
|
color: $gray-200;
|
||||||
@@ -518,11 +523,11 @@
|
|||||||
import TagsPopup from './tagsPopup';
|
import TagsPopup from './tagsPopup';
|
||||||
import { mapGetters, mapActions, mapState } from 'client/libs/store';
|
import { mapGetters, mapActions, mapState } from 'client/libs/store';
|
||||||
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
import toggleSwitch from 'client/components/ui/toggleSwitch';
|
||||||
import sortable from 'client/directives/sortable.directive';
|
|
||||||
import clone from 'lodash/clone';
|
import clone from 'lodash/clone';
|
||||||
import Datepicker from 'vuejs-datepicker';
|
import Datepicker from 'vuejs-datepicker';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
|
import draggable from 'vuedraggable';
|
||||||
|
|
||||||
import informationIcon from 'assets/svg/information.svg';
|
import informationIcon from 'assets/svg/information.svg';
|
||||||
import difficultyTrivialIcon from 'assets/svg/difficulty-trivial.svg';
|
import difficultyTrivialIcon from 'assets/svg/difficulty-trivial.svg';
|
||||||
@@ -539,9 +544,7 @@ export default {
|
|||||||
TagsPopup,
|
TagsPopup,
|
||||||
Datepicker,
|
Datepicker,
|
||||||
toggleSwitch,
|
toggleSwitch,
|
||||||
},
|
draggable,
|
||||||
directives: {
|
|
||||||
sortable,
|
|
||||||
},
|
},
|
||||||
// purpose is either create or edit, task is the task created or edited
|
// purpose is either create or edit, task is the task created or edited
|
||||||
props: ['task', 'purpose', 'challengeId', 'groupId'],
|
props: ['task', 'purpose', 'challengeId', 'groupId'],
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
import Sortable from 'sortablejs';
|
|
||||||
import uuid from 'uuid';
|
|
||||||
|
|
||||||
let emit = (vNode, eventName, data) => {
|
|
||||||
let handlers = vNode.data && vNode.data.on ||
|
|
||||||
vNode.componentOptions && vNode.componentOptions.listeners;
|
|
||||||
|
|
||||||
if (handlers && handlers[eventName]) {
|
|
||||||
handlers[eventName].fns(data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let sortableReferences = {};
|
|
||||||
|
|
||||||
function createSortable (el, vNode) {
|
|
||||||
let sortableRef = Sortable.create(el, {
|
|
||||||
filter: '.task-dropdown', // do not make the tasks dropdown draggable or it won't work
|
|
||||||
onSort: (evt) => {
|
|
||||||
emit(vNode, 'onsort', {
|
|
||||||
oldIndex: evt.oldIndex,
|
|
||||||
newIndex: evt.newIndex,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let uniqueId = uuid();
|
|
||||||
sortableReferences[uniqueId] = sortableRef;
|
|
||||||
el.dataset.sortableId = uniqueId;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
bind (el, binding, vNode) {
|
|
||||||
createSortable(el, vNode);
|
|
||||||
},
|
|
||||||
unbind (el) {
|
|
||||||
if (sortableReferences[el.dataset.sortableId]) sortableReferences[el.dataset.sortableId].destroy();
|
|
||||||
},
|
|
||||||
update (el, vNode) {
|
|
||||||
if (sortableReferences[el.dataset.sortableId] && !vNode.value) {
|
|
||||||
sortableReferences[el.dataset.sortableId].destroy();
|
|
||||||
delete sortableReferences[el.dataset.sortableId];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!sortableReferences[el.dataset.sortableId]) createSortable(el, vNode);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user