Skip to content

Instantly share code, notes, and snippets.

@mirontoli
Created March 25, 2013 22:23
Show Gist options
  • Save mirontoli/5241360 to your computer and use it in GitHub Desktop.
Save mirontoli/5241360 to your computer and use it in GitHub Desktop.
A todo webpart markup for SharePoint 2010 which uses the REST API (listdata.svc) to create, update, list and delete todos from the list Tasks. It only works in Norwegian language, because it is on of the limitations of the REST API in SharePoint 2010. This code was written for a while and uses the deprecated jQuery tmpl for rendering the todos.
<style type="text/css">
/***************************************************
Marvelous Formula (MF) WPTodo
******************************************************/
#todo-wp {
max-height: 400px;
/* todo overflow: auto or pagination */
overflow-y: auto;
}
#todo-wp .header {
border-bottom: 1px solid #D0D0D0;
padding-bottom: 5px;
margin-bottom: 10px;
}
ul#todo-container {
list-style-type: none;
padding: 0px;
margin: 0px;
}
ul#todo-container li{
margin-bottom: 5px;
}
ul#todo-container li.completed span {
text-decoration: line-through;
}
#add-todo {
background: transparent url("/_layouts/images/wptodo/add.png") no-repeat center left;
padding-left: 20px;
padding-top: 5px;
padding-bottom: 5px;
float: right;
}
#todo-form {
margin-top: 20px;
}
#todo-form input{
margin-top: 10px;
}
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://raw.github.com/jquery/jquery-tmpl/master/jquery.tmpl.min.js"></script>
<script id="todo-template" type="text/html">
<li class="{{if StatusValue == MF.L10n.Task.completed}}completed{{/if}}">
<input type="checkbox" {{if StatusValue == MF.L10n.Task.completed}}checked{{/if}}/>
<span>{{= this.data[MF.L10n.Task.title]}}</span>
</li>
</script>
<div id="todo-wp">
<div class="header">
<div id="add-todo" class="pointer">Legg til</div>
<div class="main-info">
Å gjøre</div>
</div>
<div id="todo-message"></div>
<ul id="todo-container">
</ul>
<div id="todo-form" class="center modalform-data s4-die">
<input type="text" class="todo-text" /><br />
<input type="button"
value="save" class="save"
onclick="return SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, {title: jQuery(this).siblings('.todo-text').val()});" />
<input type="button" value="cancel"
onclick="SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, {});" />
</div>
</div>
<script type="text/javascript">
var MF = {};
/***************************************************
Marvelous Formula (MF) json and rest
******************************************************/
MF.Utils = {
//changes request header for updating through REST
//http://msdn.microsoft.com/en-us/library/ff798339.aspx
beforeSendFunction: function (xhr) {
xhr.setRequestHeader("If-Match", "*");
// Using MERGE so that the entire entity doesn't need to be sent over the wire.
xhr.setRequestHeader("X-HTTP-Method", 'MERGE');
}
};
MF.L10n = {
Task: {
noTasksMessage: "Det finnes ingen oppgaver akkurat nå",
addTask: "Legg til opgave",
errorMsgWithRetry: "Oops, it didn't work as expected... Trying after {0} sec..",
// don't translate following properties of Task,
// just copy values prefixed with Tasks_ from $Resoures:core.resx
// this is used to retrieve and update todos with listdata.svc web service
listName: "Oppgaver", //$Resoures:core, taskList
completed: "Fullført", //$Resoures:core, Tasks_Completed
inProgress: "Pågår", //$Resoures:core, Tasks_InProgress
modified: "Endret", //$Resoures:core, Modified
created: "Opprettet", //$Resoures:core, Created
title: "Tittel", //$Resoures:core, Title
assignedToId: "TilordnetTilId" //? "assignedToId" in lang=en (1033)
}
};
MF.Todo = {
userId: _spPageContextInfo.userId,
taskUrl: undefined,
tryCounter: 0,
$msg: undefined,
$todoTmpl: undefined,
$todoContainer: undefined,
error: function (xhr) {
// see if it is culture crock after restart of the server
if (xhr.responseText.match(/No property .* exists/i)) {
MF.Todo.retrieveTodos();
return;
}
MF.Todo.tryCounter++;
if (MF.Todo.tryCounter < 4) {
var errorMsg = String.format(MF.L10n.Task.errorMsgWithRetry, MF.Todo.tryCounter * 10);
MF.Todo.showTodoMessage(errorMsg);
setTimeout(MF.Todo.retrieveTodos, 10000 * MF.Todo.tryCounter);
}
errorCallback(xhr, jQuery("#todo-container").get(0));
},
retrieveTodos: function () {
MF.Todo.showTodoMessage("");
MF.Todo.ensureTmplAndContainer();
MF.Todo.$todoContainer.showLoadingImage();
MF.Todo.getMyNotCompletedTasks();
},
getMyNotCompletedTasks: function () {
MF.Todo.taskUrl = MF.Todo.taskUrl || MF.Constants.listDataServiceUrl + MF.L10n.Task.listName;
var oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
var isoDateOneWeekAgo = oneWeekAgo.toISOString();
var filter = String.format("{0} eq {1} and (StatusValue ne '{2}' or {3} ge datetime'{4}')",
MF.L10n.Task.assignedToId,
MF.Todo.userId,
MF.L10n.Task.completed,
MF.L10n.Task.modified,
isoDateOneWeekAgo);
var orderby = String.format("StatusValue desc, {0} desc", MF.L10n.Task.created);
$.ajax({
type: 'GET',
url: MF.Todo.taskUrl,
contentType: 'application/json; charset=utf-8',
async: true,
dataType: "json",
cache: false,
data: { $filter: filter, $orderby: orderby },
success: MF.Todo.renderTasks,
error: MF.Todo.error
});
},
renderTasks: function (data) {
MF.Todo.$todoContainer.empty();
MF.Todo.$todoContainer.removeLoadingImage();
var tasks = data.d.results;
if (tasks.length > 0) {
MF.Todo.appendTasks(data.d.results);
}
else {
MF.Todo.showTodoMessage(MF.L10n.Task.noTasksMessage);
}
MF.Todo.addClickListenerToAddButton();
MF.Todo.addShortcuts();
},
todoModalCallback: function (result, value) {
if (result == SP.UI.DialogResult.OK) {
MF.Todo.createNewTask(value);
}
},
createNewTask: function (value) {
if (value.title !== undefined) {
var task = {};
task[MF.L10n.Task.title] = value.title;
task[MF.L10n.Task.assignedToId] = MF.Todo.userId;
task.StatusValue = MF.L10n.Task.inProgress;
var body = MF.Utils.serialize(task);
jQuery.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
processData: false,
url: MF.Todo.taskUrl,
data: body,
dataType: "json",
converters: { "text json": MF.Utils.deserialize },
success: function (data) {
MF.Todo.prependTasks([data.d]);
},
error: MF.Todo.error
});
}
},
changeStatus: function () {
var $input = jQuery(this);
var $li = $input.parents("li");
var checked = $input.is(":checked");
var todo = $input.tmplItem().data;
var id = todo.ID;
var mods = {};
mods.StatusValue = checked ? MF.L10n.Task.completed : MF.L10n.Task.inProgress;
var body = MF.Utils.serialize(mods);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
processData: false,
beforeSend: MF.Utils.beforeSendFunction,
url: MF.Todo.taskUrl + "(" + id + ")",
data: body,
dataType: "json",
success: function () {
$li.toggleClass("completed");
},
error: MF.Todo.error
});
},
showTodoMessage: function (msg) {
MF.Todo.$msg = MF.Todo.$msg || jQuery("#todo-message");
MF.Todo.$msg.empty();
MF.Todo.$msg.text(msg);
},
appendTasks: function (tasks) {
MF.Todo.ensureTmplAndContainer();
jQuery.tmpl(MF.Todo.$todoTmpl, tasks).appendTo(MF.Todo.$todoContainer).children("input").change(MF.Todo.changeStatus);
},
prependTasks: function (tasks) {
MF.Todo.ensureTmplAndContainer();
MF.Todo.showTodoMessage("");
jQuery.tmpl(MF.Todo.$todoTmpl, tasks).prependTo(MF.Todo.$todoContainer).children("input").change(MF.Todo.changeStatus);
},
addClickListenerToAddButton: function () {
jQuery("#add-todo").live({
click: function () {
var $form = jQuery("#todo-form").clone(true);
$form.children(".todo-text").keydown(function (e) {
if (e.which == 13) {
jQuery(this).siblings(".save").click();
}
});
setTimeout(function () { jQuery(".ms-dlgFrameContainer .todo-text").focus(); }, 500);
var t = $form.toggleClass("s4-die").get(0);
var options = {
html: t,
title: MF.L10n.Task.addTask,
dialogReturnValueCallback: MF.Todo.todoModalCallback,
height: 150
};
SP.UI.ModalDialog.showModalDialog(options);
}
});
},
addShortcuts: function () {
//add keyboard shortcut
jQuery(document).keyup(function (e) {
if (e.which == 18) MF.UI.isAlt = false;
});
jQuery(document).keydown(function (e) {
if (e.which == 18) MF.UI.isAlt = true;
// Alt-L
if (e.which == 76 && MF.UI.isAlt == true) {
jQuery("#add-todo").click();
return false;
}
if (e.which == 27) { //ESC
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, {});
}
});
},
ensureTmplAndContainer: function () {
MF.Todo.$todoTmpl = MF.Todo.$todoTmpl || jQuery("#todo-template").template();
MF.Todo.$todoContainer = MF.Todo.$todoContainer || jQuery("#todo-container");
}
};
jQuery(document).ready(function () {
MF.Todo.retrieveTodos();
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment