Updated task service to use api v3 (#7136)

* Updated task service to use api v3

* Add user.ops functions back

* Removed extra parameter
This commit is contained in:
Keith Holliday
2016-05-08 09:52:43 -05:00
committed by Matteo Pagliazzi
parent 78a8eea79a
commit 4c37417bd4
9 changed files with 363 additions and 63 deletions

View File

@@ -1,22 +1,147 @@
'use strict'; 'use strict';
describe('Tasks Service', function() { describe('Tasks Service', function() {
var rootScope, tasks, user; var rootScope, tasks, user, $httpBackend;
var apiV3Prefix = 'api/v3/tasks';
beforeEach(function() { beforeEach(function() {
module(function($provide) { module(function($provide) {
user = specHelper.newUser(); user = specHelper.newUser();
$provide.value('User', {user: user}); $provide.value('User', {user: user});
}); });
inject(function(_$rootScope_, Tasks, User) { inject(function(_$httpBackend_, _$rootScope_, Tasks, User) {
$httpBackend = _$httpBackend_;
rootScope = _$rootScope_; rootScope = _$rootScope_;
rootScope.charts = {}; rootScope.charts = {};
tasks = Tasks; tasks = Tasks;
}); });
}); });
it('calls get user tasks endpoint', function() {
$httpBackend.expectGET(apiV3Prefix + '/user').respond({});
tasks.getUserTasks();
$httpBackend.flush();
});
it('calls post user tasks endpoint', function() {
$httpBackend.expectPOST(apiV3Prefix + '/user').respond({});
tasks.createUserTasks();
$httpBackend.flush();
});
it('calls get challenge tasks endpoint', function() {
var challengeId = 1;
$httpBackend.expectGET(apiV3Prefix + '/challenge/' + challengeId).respond({});
tasks.getChallengeTasks(challengeId);
$httpBackend.flush();
});
it('calls create challenge tasks endpoint', function() {
var challengeId = 1;
$httpBackend.expectPOST(apiV3Prefix + '/challenge/' + challengeId).respond({});
tasks.createChallengeTasks(challengeId, {});
$httpBackend.flush();
});
it('calls get task endpoint', function() {
var taskId = 1;
$httpBackend.expectGET(apiV3Prefix + '/' + taskId).respond({});
tasks.getTask(taskId);
$httpBackend.flush();
});
it('calls update task endpoint', function() {
var taskId = 1;
$httpBackend.expectPUT(apiV3Prefix + '/' + taskId).respond({});
tasks.updateTask(taskId, {});
$httpBackend.flush();
});
it('calls delete task endpoint', function() {
var taskId = 1;
$httpBackend.expectDELETE(apiV3Prefix + '/' + taskId).respond({});
tasks.deleteTask(taskId);
$httpBackend.flush();
});
it('calls score task endpoint', function() {
var taskId = 1;
var direction = "down";
$httpBackend.expectPOST(apiV3Prefix + '/' + taskId + '/score/' + direction).respond({});
tasks.scoreTask(taskId, direction);
$httpBackend.flush();
});
it('calls move task endpoint', function() {
var taskId = 1;
var position = 0;
$httpBackend.expectPOST(apiV3Prefix + '/' + taskId + '/move/to/' + position).respond({});
tasks.moveTask(taskId, position);
$httpBackend.flush();
});
it('calls add check list item endpoint', function() {
var taskId = 1;
$httpBackend.expectPOST(apiV3Prefix + '/' + taskId + '/checklist').respond({});
tasks.addChecklistItem(taskId, {});
$httpBackend.flush();
});
it('calls score check list item endpoint', function() {
var taskId = 1;
var itemId = 2;
$httpBackend.expectPOST(apiV3Prefix + '/' + taskId + '/checklist/' + itemId + '/score').respond({});
tasks.scoreCheckListItem(taskId, itemId);
$httpBackend.flush();
});
it('calls update check list item endpoint', function() {
var taskId = 1;
var itemId = 2;
$httpBackend.expectPUT(apiV3Prefix + '/' + taskId + '/checklist/' + itemId).respond({});
tasks.updateChecklistItem(taskId, itemId, {});
$httpBackend.flush();
});
it('calls remove check list item endpoint', function() {
var taskId = 1;
var itemId = 2;
$httpBackend.expectDELETE(apiV3Prefix + '/' + taskId + '/checklist/' + itemId).respond({});
tasks.removeChecklistItem(taskId, itemId);
$httpBackend.flush();
});
it('calls add tag to list item endpoint', function() {
var taskId = 1;
var tagId = 2;
$httpBackend.expectPOST(apiV3Prefix + '/' + taskId + '/tags/' + tagId).respond({});
tasks.addTagToTask(taskId, tagId);
$httpBackend.flush();
});
it('calls remove tag to list item endpoint', function() {
var taskId = 1;
var tagId = 2;
$httpBackend.expectDELETE(apiV3Prefix + '/' + taskId + '/tags/' + tagId).respond({});
tasks.removeTagFromTask(taskId, tagId);
$httpBackend.flush();
});
it('calls unlink task endpoint', function() {
var taskId = 1;
var keep = "keep-all";
$httpBackend.expectPOST(apiV3Prefix + '/unlink/' + taskId + '?keep=' + keep).respond({});
tasks.unlinkTask(taskId);
$httpBackend.flush();
});
it('calls clear completed todo task endpoint', function() {
$httpBackend.expectPOST(apiV3Prefix + '/clearCompletedTodos').respond({});
tasks.clearCompletedTodos();
$httpBackend.flush();
});
describe('editTask', function() { describe('editTask', function() {
var task; var task;
@@ -82,24 +207,22 @@ describe('Tasks Service', function() {
expect(clonedTask.attribute).to.eql(task.attribute); expect(clonedTask.attribute).to.eql(task.attribute);
}); });
it('does not clone original task\'s id or _id', function() { it('does not clone original task\'s _id', function() {
var task = specHelper.newTask(); var task = specHelper.newTask();
var clonedTask = tasks.cloneTask(task); var clonedTask = tasks.cloneTask(task);
expect(clonedTask.id).to.exist;
expect(clonedTask.id).to.not.eql(task.id);
expect(clonedTask._id).to.exist; expect(clonedTask._id).to.exist;
expect(clonedTask._id).to.not.eql(task._id); expect(clonedTask._id).to.not.eql(task._id);
}); });
it('does not clone original task\'s dateCreated attribute', function() { it('does not clone original task\'s dateCreated attribute', function() {
var task = specHelper.newTask({ var task = specHelper.newTask({
dateCreated: new Date(2014, 5, 1, 1, 1, 1, 1), createdAt: new Date(2014, 5, 1, 1, 1, 1, 1),
}); });
var clonedTask = tasks.cloneTask(task); var clonedTask = tasks.cloneTask(task);
expect(clonedTask.dateCreated).to.exist; expect(clonedTask.createdAt).to.exist;
expect(clonedTask.dateCreated).to.not.eql(task.dateCreated); expect(clonedTask.createdAt).to.not.eql(task.createdAt);
}); });
it('does not clone original task\'s value', function() { it('does not clone original task\'s value', function() {

View File

@@ -180,12 +180,20 @@ window.habitrpg = angular.module('habitrpg',
url: '/:cid', url: '/:cid',
templateUrl: 'partials/options.social.challenges.detail.html', templateUrl: 'partials/options.social.challenges.detail.html',
title: env.t('titleChallenges'), title: env.t('titleChallenges'),
controller: ['$scope', 'Challenges', '$stateParams', controller: ['$scope', 'Challenges', '$stateParams', 'Tasks',
function ($scope, Challenges, $stateParams) { function ($scope, Challenges, $stateParams, Tasks) {
Challenges.getChallenge($stateParams.cid) Challenges.getChallenge($stateParams.cid)
.then(function (response) { .then(function (response) {
$scope.obj = $scope.challenge = response.data.data; $scope.obj = $scope.challenge = response.data.data;
$scope.challenge._locked = true; $scope.challenge._locked = true;
return Tasks.getChallengeTasks($scope.challenge._id);
})
.then(function (response) {
var tasks = response.data.data;
tasks.forEach(function (element, index, array) {
if (!$scope.challenge[element.type + 's']) $scope.challenge[element.type + 's'] = [];
$scope.challenge[element.type + 's'].push(element);
})
}); });
}] }]
}) })
@@ -193,12 +201,20 @@ window.habitrpg = angular.module('habitrpg',
url: '/:cid/edit', url: '/:cid/edit',
templateUrl: 'partials/options.social.challenges.detail.html', templateUrl: 'partials/options.social.challenges.detail.html',
title: env.t('titleChallenges'), title: env.t('titleChallenges'),
controller: ['$scope', 'Challenges', '$stateParams', controller: ['$scope', 'Challenges', '$stateParams', 'Tasks',
function ($scope, Challenges, $stateParams) { function ($scope, Challenges, $stateParams, Tasks) {
Challenges.getChallenge($stateParams.cid) Challenges.getChallenge($stateParams.cid)
.then(function (response) { .then(function (response) {
$scope.obj = $scope.challenge = response.data.data; $scope.obj = $scope.challenge = response.data.data;
$scope.challenge._locked = false; $scope.challenge._locked = false;
return Tasks.getChallengeTasks($scope.challenge._id);
})
.then(function (response) {
var tasks = response.data.data;
tasks.forEach(function (element, index, array) {
if (!$scope.challenge[element.type + 's']) $scope.challenge[element.type + 's'] = [];
$scope.challenge[element.type + 's'].push(element);
})
}); });
}] }]
}) })

View File

@@ -132,9 +132,16 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
$state.transitionTo('options.social.challenges.detail', { cid: _challenge._id }, { $state.transitionTo('options.social.challenges.detail', { cid: _challenge._id }, {
reload: true, inherit: false, notify: true reload: true, inherit: false, notify: true
}); });
var challengeTasks = [];
challengeTasks.concat(challenge.todos);
challengeTasks.concat(challenge.habits);
challengeTasks.concat(challenge.dailys);
challengeTasks.concat(challenge.reqards);
Tasks.createChallengeTasks(_challenge._id, challengeTasks);
}); });
} else { } else {
Challenges.updateChallenge(challenge) Challenges.updateChallenge(challenge._id, challenge)
.then(function (response) { .then(function (response) {
var _challenge = response.data.data; var _challenge = response.data.data;
$state.transitionTo('options.social.challenges.detail', { cid: _challenge._id }, { $state.transitionTo('options.social.challenges.detail', { cid: _challenge._id }, {
@@ -223,19 +230,19 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
//------------------------------------------------------------ //------------------------------------------------------------
// Tasks // Tasks
//------------------------------------------------------------ //------------------------------------------------------------
$scope.addTask = function(addTo, listDef, challenge) {
$scope.addTask = function(addTo, listDef) {
var task = Shared.taskDefaults({text: listDef.newTask, type: listDef.type}); var task = Shared.taskDefaults({text: listDef.newTask, type: listDef.type});
addTo.unshift(task); Tasks.createChallengeTasks(challenge._id, task);
//User.log({op: "addTask", data: task}); //TODO persist if (!challenge[task.type + 's']) challenge[task.type + 's'] = [];
challenge[task.type + 's'].push(task);
delete listDef.newTask; delete listDef.newTask;
}; };
$scope.removeTask = function(task, list) { $scope.removeTask = function(task, list) {
if (!confirm(window.env.t('sureDelete', {taskType: window.env.t(task.type), taskText: task.text}))) return; if (!confirm(window.env.t('sureDelete', {taskType: window.env.t(task.type), taskText: task.text}))) return;
//TODO persist Tasks.deleteTask(task._id);
// User.log({op: "delTask", data: task}); var index = challenge[task.type + 's'].indexOf(task);
_.remove(list, task); challenge[task.type + 's'].splice(index, 1);
}; };
$scope.saveTask = function(task){ $scope.saveTask = function(task){
@@ -407,7 +414,8 @@ habitrpg.controller("ChallengesCtrl", ['$rootScope','$scope', 'Shared', 'User',
function _getChallenges() { function _getChallenges() {
if ($scope.cid) { if ($scope.cid) {
Challenges.getChallenge($scope.cid) Challenges.getChallenge($scope.cid)
.then(function (challenge) { .then(function (response) {
var challenge = response.data.data;
$scope.challenges = [challenge]; $scope.challenges = [challenge];
}); });
} else { } else {

View File

@@ -46,7 +46,9 @@ habitrpg.controller("PartyCtrl", ['$rootScope','$scope','Groups','Chat','User','
} }
} }
Chat.markChatSeen($scope.group._id); if ($scope.group && $scope.group._id) {
Chat.markChatSeen($scope.group._id);
}
$scope.create = function(group) { $scope.create = function(group) {
if (!group.name) group.name = env.t('possessiveParty', {name: User.user.profile.name}); if (!group.name) group.name = env.t('possessiveParty', {name: User.user.profile.name});

View File

@@ -33,10 +33,11 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
var newTask = { var newTask = {
text: task, text: task,
type: listDef.type, type: listDef.type,
tags: _.transform(User.user.filters, function(m,v,k){ tags: _.transform(User.user.filters, function(m, v, k) {
if (v) m[k]=v; if (v) m.push(v);
}) }),
}; };
User.user.ops.addTask({body:newTask}); User.user.ops.addTask({body:newTask});
} }
@@ -70,7 +71,9 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
/** /**
* Add the new task to the actions log * Add the new task to the actions log
*/ */
$scope.clearDoneTodos = function() {}; $scope.clearDoneTodos = function() {
Tasks.clearCompletedTodos();
};
/** /**
* Pushes task to top or bottom of list * Pushes task to top or bottom of list
@@ -97,12 +100,20 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
}; };
$scope.saveTask = function(task, stayOpen, isSaveAndClose) { $scope.saveTask = function(task, stayOpen, isSaveAndClose) {
if (task.checklist) //@TODO: We will need to fix tag saving when user service is ported since tags are attached at the user level
task.checklist = _.filter(task.checklist,function(i){return !!i.text});
if (task.checklist) {
task.checklist = _.filter(task.checklist, function(i) {return !!i.text});
}
User.user.ops.updateTask({params:{id:task.id},body:task}); User.user.ops.updateTask({params:{id:task.id},body:task});
if (!stayOpen) task._editing = false; if (!stayOpen) task._editing = false;
if (isSaveAndClose)
if (isSaveAndClose) {
$("#task-" + task.id).parent().children('.popover').removeClass('in'); $("#task-" + task.id).parent().children('.popover').removeClass('in');
}
if (task.type == 'habit') Guide.goto('intro', 3); if (task.type == 'habit') Guide.goto('intro', 3);
}; };
@@ -120,9 +131,8 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
}; };
$scope.unlink = function(task, keep) { $scope.unlink = function(task, keep) {
// TODO move this to userServices, turn userSerivces.user into ng-resource Tasks.unlinkTask(task.id, keep)
$http.post(ApiUrl.get() + '/api/v2/user/tasks/' + task.id + '/unlink?keep=' + keep) .success(function () {
.success(function(){
User.log({}); User.log({});
}); });
}; };
@@ -157,50 +167,57 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
$('#task-'+task.id+' .checklist-form input[type="text"]')[index].focus(); $('#task-'+task.id+' .checklist-form input[type="text"]')[index].focus();
}); });
} }
$scope.addChecklist = function(task) { $scope.addChecklist = function(task) {
task.checklist = [{completed:false,text:""}]; task.checklist = [{completed:false, text:""}];
focusChecklist(task,0); focusChecklist(task,0);
} }
$scope.addChecklistItem = function(task,$event,$index) {
$scope.addChecklistItem = function(task, $event, $index) {
if (!task.checklist[$index].text) { if (!task.checklist[$index].text) {
// Don't allow creation of an empty checklist item // Don't allow creation of an empty checklist item
// TODO Provide UI feedback that this item is still blank // TODO Provide UI feedback that this item is still blank
} else if ($index == task.checklist.length-1){ } else if ($index == task.checklist.length - 1) {
User.user.ops.updateTask({params:{id:task.id},body:task}); // don't preen the new empty item User.user.ops.updateTask({params:{id:task.id},body:task});
task.checklist.push({completed:false,text:''}); task.checklist.push({completed: false, text: ''});
focusChecklist(task,task.checklist.length-1); focusChecklist(task, task.checklist.length - 1);
} else { } else {
$scope.saveTask(task,true); $scope.saveTask(task, true);
focusChecklist(task,$index+1); focusChecklist(task, $index + 1);
} }
} }
$scope.removeChecklistItem = function(task,$event,$index,force){
$scope.removeChecklistItem = function(task, $event, $index, force){
// Remove item if clicked on trash icon // Remove item if clicked on trash icon
if (force) { if (force) {
task.checklist.splice($index,1); Tasks.removeChecklistItem(task.id, task.checklist[$index]._id);
$scope.saveTask(task,true); task.checklist.splice($index, 1);
} else if (!task.checklist[$index].text) { } else if (!task.checklist[$index].text) {
// User deleted all the text and is now wishing to delete the item // User deleted all the text and is now wishing to delete the item
// saveTask will prune the empty item // saveTask will prune the empty item
$scope.saveTask(task,true); Tasks.removeChecklistItem(task.id, task.checklist[$index]._id);
// Move focus if the list is still non-empty // Move focus if the list is still non-empty
if ($index > 0) if ($index > 0)
focusChecklist(task,$index-1); focusChecklist(task, $index-1);
// Don't allow the backspace key to navigate back now that the field is gone // Don't allow the backspace key to navigate back now that the field is gone
$event.preventDefault(); $event.preventDefault();
} }
} }
$scope.swapChecklistItems = function(task, oldIndex, newIndex) { $scope.swapChecklistItems = function(task, oldIndex, newIndex) {
var toSwap = task.checklist.splice(oldIndex, 1)[0]; var toSwap = task.checklist.splice(oldIndex, 1)[0];
task.checklist.splice(newIndex, 0, toSwap); task.checklist.splice(newIndex, 0, toSwap);
$scope.saveTask(task, true); $scope.saveTask(task, true);
} }
$scope.navigateChecklist = function(task,$index,$event){ $scope.navigateChecklist = function(task,$index,$event){
focusChecklist(task, $event.keyCode == '40' ? $index+1 : $index-1); focusChecklist(task, $event.keyCode == '40' ? $index+1 : $index-1);
} }
$scope.checklistCompletion = function(checklist){ $scope.checklistCompletion = function(checklist){
return _.reduce(checklist,function(m,i){return m+(i.completed ? 1 : 0);},0) return _.reduce(checklist,function(m,i){return m+(i.completed ? 1 : 0);},0)
} }
$scope.collapseChecklist = function(task) { $scope.collapseChecklist = function(task) {
task.collapseChecklist = !task.collapseChecklist; task.collapseChecklist = !task.collapseChecklist;
$scope.saveTask(task,true); $scope.saveTask(task,true);
@@ -224,7 +241,6 @@ habitrpg.controller("TasksCtrl", ['$scope', '$rootScope', '$location', 'User','N
User.user.ops.buy({params:{key:item.key}}); User.user.ops.buy({params:{key:item.key}});
}; };
/* /*
------------------------ ------------------------
Hiding Tasks Hiding Tasks

View File

@@ -1,19 +1,138 @@
'use strict'; 'use strict';
(function(){ var TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'dateCreated', 'history', 'id', 'streak', 'createdAt'];
var TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'dateCreated', 'history', 'id', 'streak'];
angular angular.module('habitrpg')
.module('habitrpg') .factory('Tasks', ['$rootScope', 'Shared', 'User', '$http',
.factory('Tasks', tasksFactory); function tasksFactory($rootScope, Shared, User, $http) {
tasksFactory.$inject = [ function getUserTasks () {
'$rootScope', return $http({
'Shared', method: 'GET',
'User' url: 'api/v3/tasks/user',
]; });
};
function tasksFactory($rootScope, Shared, User) { function createUserTasks (taskDetails) {
return $http({
method: 'POST',
url: 'api/v3/tasks/user',
data: taskDetails,
});
};
function getChallengeTasks (challengeId) {
return $http({
method: 'GET',
url: 'api/v3/tasks/challenge/' + challengeId,
});
};
function createChallengeTasks (challengeId, taskDetails) {
return $http({
method: 'POST',
url: 'api/v3/tasks/challenge/' + challengeId,
data: taskDetails,
});
};
function getTask (taskId) {
return $http({
method: 'GET',
url: 'api/v3/tasks/' + taskId,
});
};
function updateTask (taskId, taskDetails) {
return $http({
method: 'PUT',
url: 'api/v3/tasks/' + taskId,
data: taskDetails,
});
};
function deleteTask (taskId) {
return $http({
method: 'DELETE',
url: 'api/v3/tasks/' + taskId,
});
};
function scoreTask (taskId, direction) {
return $http({
method: 'POST',
url: 'api/v3/tasks/' + taskId + '/score/' + direction,
});
};
function moveTask (taskId, position) {
return $http({
method: 'POST',
url: 'api/v3/tasks/' + taskId + '/move/to/' + position,
});
};
function addChecklistItem (taskId, checkListItem) {
return $http({
method: 'POST',
url: 'api/v3/tasks/' + taskId + '/checklist',
data: checkListItem,
});
};
function scoreCheckListItem (taskId, itemId) {
return $http({
method: 'POST',
url: 'api/v3/tasks/' + taskId + '/checklist/' + itemId + '/score',
});
};
function updateChecklistItem (taskId, itemId, itemDetails) {
return $http({
method: 'PUT',
url: 'api/v3/tasks/' + taskId + '/checklist/' + itemId,
data: itemDetails,
});
};
function removeChecklistItem (taskId, itemId) {
return $http({
method: 'DELETE',
url: 'api/v3/tasks/' + taskId + '/checklist/' + itemId,
});
};
function addTagToTask (taskId, tagId) {
return $http({
method: 'POST',
url: 'api/v3/tasks/' + taskId + '/tags/' + tagId,
});
};
function removeTagFromTask (taskId, tagId) {
return $http({
method: 'DELETE',
url: 'api/v3/tasks/' + taskId + '/tags/' + tagId,
});
};
function unlinkTask (taskId, keep) {
if (!keep) {
keep = "keep-all";
}
return $http({
method: 'POST',
url: 'api/v3/tasks/unlink/' + taskId + '?keep=' + keep,
});
};
function clearCompletedTodos () {
return $http({
method: 'POST',
url: 'api/v3/tasks/clearCompletedTodos',
});
};
function editTask(task) { function editTask(task) {
task._editing = !task._editing; task._editing = !task._editing;
@@ -46,8 +165,24 @@
} }
return { return {
getUserTasks: getUserTasks,
createUserTasks: createUserTasks,
getChallengeTasks: getChallengeTasks,
createChallengeTasks: createChallengeTasks,
getTask: getTask,
updateTask: updateTask,
deleteTask: deleteTask,
scoreTask: scoreTask,
moveTask: moveTask,
addChecklistItem: addChecklistItem,
scoreCheckListItem: scoreCheckListItem,
updateChecklistItem: updateChecklistItem,
removeChecklistItem: removeChecklistItem,
addTagToTask: addTagToTask,
removeTagFromTask: removeTagFromTask,
unlinkTask: unlinkTask,
clearCompletedTodos: clearCompletedTodos,
editTask: editTask, editTask: editTask,
cloneTask: cloneTask cloneTask: cloneTask
}; };
} }]);
})();

View File

@@ -1,5 +1,5 @@
fieldset.option-group(ng-if='!$state.includes("options.social.challenges")') fieldset.option-group(ng-if='!$state.includes("options.social.challenges")')
p.option-title.mega(ng-class='{active: task._tags}', ng-click='task._tags = !task._tags', tooltip=env.t('expandCollapse'))=env.t('tags') p.option-title.mega(ng-class='{active: task._tags}', ng-click='task._tags = !task._tags', tooltip=env.t('expandCollapse'))=env.t('tags')
label.checkbox(ng-repeat='tag in user.tags', ng-if='task._tags') label.checkbox(ng-repeat='tag in user.tags', ng-if='task._tags')
input(type='checkbox', ng-model='task.tags[tag.id]') input(type='checkbox', ng-model='task.tags[tag.id]', ng-checked="task.tags.indexOf(tag.id) !== -1")
markdown(text='tag.name') markdown(text='tag.name')

View File

@@ -43,7 +43,7 @@
span.glyphicon.glyphicon-bullhorn(tooltip=env.t('challenge')) span.glyphicon.glyphicon-bullhorn(tooltip=env.t('challenge'))
|   |  
// delete // delete
a(ng-if='!task.challenge.id', ng-click='removeTask(task, obj[list.type+"s"])', tooltip=env.t('delete')) a(ng-if='!task.challenge.id', ng-click='removeTask(task, $index)', tooltip=env.t('delete'))
span.glyphicon.glyphicon-trash span.glyphicon.glyphicon-trash
|   |  

View File

@@ -1,4 +1,4 @@
form.task-add(name='new{{list.type}}form', ng-hide='obj._locked', ng-submit='addTask(obj[list.type+"s"],list)', novalidate) form.task-add(name='new{{list.type}}form', ng-hide='obj._locked', ng-submit='addTask(obj[list.type+"s"], list, obj)', novalidate)
textarea(rows='6', focus-element='list.bulk && list.focus', ng-model='list.newTask', placeholder='{{list.placeHolderBulk}}', ng-if='list.bulk', ui-keydown='{"meta-enter ctrl-enter":"addTask(obj[list.type+\'s\'],list)"}', required) textarea(rows='6', focus-element='list.bulk && list.focus', ng-model='list.newTask', placeholder='{{list.placeHolderBulk}}', ng-if='list.bulk', ui-keydown='{"meta-enter ctrl-enter":"addTask(obj[list.type+\'s\'],list)"}', required)
input(type='text', focus-element='!list.bulk && list.focus', ng-model='list.newTask', placeholder='{{list.placeHolder}}', ng-if='!list.bulk', required) input(type='text', focus-element='!list.bulk && list.focus', ng-model='list.newTask', placeholder='{{list.placeHolder}}', ng-if='!list.bulk', required)
button(type='submit', ng-disabled='new{{list.type}}form.$invalid') button(type='submit', ng-disabled='new{{list.type}}form.$invalid')