mirror of
https://github.com/cosmocode/do.git
synced 2025-07-24 09:58:58 +00:00
536 lines
18 KiB
JavaScript
536 lines
18 KiB
JavaScript
var PluginDo = {
|
|
|
|
/*******************************
|
|
* General functions *
|
|
*******************************/
|
|
|
|
/**
|
|
* Create a floating, draggable overlay
|
|
*
|
|
* @param {string} title The title line
|
|
* @param {string} id The id to assign to the overlay
|
|
* @param {string} fieldsetcontent Content of the fieldset as HTML
|
|
* @param {string} submitcaption Label for the submit button
|
|
* @param {Function} submitaction callback What to do when submit is pressed
|
|
* @returns HTMLElement The created overlay DOMObject
|
|
*/
|
|
createOverlay: function (title, id, fieldsetcontent, submitcaption, submitaction) {
|
|
// create overlay div
|
|
var $dialog = jQuery(document.createElement('div'))
|
|
.dialog({
|
|
autoOpen: false,
|
|
draggable: true,
|
|
title: title,
|
|
resizable: false
|
|
})
|
|
.html('<fieldset>' +
|
|
fieldsetcontent +
|
|
'<p class="button_wrap"><button class="button plugin_do_closetask">' +
|
|
submitcaption +
|
|
'</button></p>' +
|
|
'</fieldset>')
|
|
.parent()
|
|
.attr('id', id)
|
|
.addClass('plugin_do_popup')
|
|
.hide()
|
|
.appendTo('.dokuwiki:first');
|
|
|
|
// add event handlers
|
|
jQuery('#' + id + ' .ui-dialog-titlebar-close').click(function () { // close button
|
|
$dialog.toggle();
|
|
});
|
|
|
|
$dialog
|
|
.keydown(function (e) {
|
|
if (e.keyCode !== 13) { //Enter
|
|
return true;
|
|
}
|
|
|
|
submitaction();
|
|
$dialog.hide();
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
return false;
|
|
})
|
|
.find('.plugin_do_closetask').click(function (e) {
|
|
submitaction();
|
|
$dialog.hide();
|
|
|
|
e.preventDefault();
|
|
return false;
|
|
});
|
|
|
|
return $dialog;
|
|
},
|
|
|
|
/********************************************
|
|
* functions for interactive tasks in pages *
|
|
********************************************/
|
|
|
|
/**
|
|
* Toggle status of task, when symbol of task is clicked
|
|
*
|
|
* @param event
|
|
* @returns {boolean}
|
|
*/
|
|
toggle_status: function (event) {
|
|
if (jQuery(this).parent().hasClass('plugin_do_done')) {
|
|
//mark undone
|
|
PluginDo.save_update_SingleTask(this);
|
|
|
|
} else {
|
|
//mark done, popup for commitmessage
|
|
var $popup = jQuery('#do__commit_popup')
|
|
.toggle()
|
|
.css({
|
|
'position': 'absolute',
|
|
'top': (event.pageY + 10) + 'px',
|
|
'left': (event.pageX - 150) + 'px'
|
|
});
|
|
$popup[0].__me = this;
|
|
jQuery('#do__popup_msg').focus();
|
|
}
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* callback performs close action of Close dialog
|
|
*/
|
|
closeSingleTask: function () {
|
|
PluginDo.save_update_SingleTask(jQuery('#do__commit_popup')[0].__me);
|
|
jQuery('#do__popup_msg').val('');
|
|
},
|
|
|
|
/**
|
|
* Switch the status of a image src
|
|
*
|
|
* @param {boolean} done true for done tasks, false for undone
|
|
* @param {jQuery} $applyto jQuery object with DOM elements where to update images
|
|
*/
|
|
switchDoNr: function (done, $applyto) {
|
|
var newImg = done ? 'undone.png' : 'done.png';
|
|
|
|
$applyto.find('img').attr('src', DOKU_BASE + 'lib/plugins/do/pix/' + newImg);
|
|
},
|
|
|
|
/**
|
|
* Set the task title
|
|
*
|
|
* @param {Array} assignees assignees for the task, undefined for autodetect
|
|
* @param {string} due the task's due date, undefined for autodetect
|
|
* @param {string} closedby who closed the task, undefined for not closed, yet
|
|
* @param {string} closedon when was the task closed, undefined for not closed, yet
|
|
* @param {jQuery} $applyto jQuery object with DOM elements where to add the title tag, undefined for rootNode
|
|
*/
|
|
buildTitle: function ($applyto, assignees, due, closedby, closedon) {
|
|
var titelNo = 4;
|
|
|
|
// determine assignees
|
|
if (!assignees || !assignees.length) {
|
|
//take the assignees of the first task or table row when tasks are duplicated
|
|
var $assigneeobjs = $applyto.first().find('span.plugin_do_meta_user');
|
|
if ($assigneeobjs.length === 0) {
|
|
$assigneeobjs = $applyto.parent('td').parent().first().find('td.plugin_do_assignee');
|
|
}
|
|
assignees = [];
|
|
$assigneeobjs.each(function (i, assignee) {
|
|
assignees.push(PluginDo.stripTags(jQuery(assignee).html()));
|
|
});
|
|
}
|
|
if (assignees.length > 0) {
|
|
titelNo -= 2;
|
|
}
|
|
|
|
// determine due date
|
|
if (!due) {
|
|
var $due = $applyto.first().find('span.plugin_do_meta_date');
|
|
if ($due.length === 0) {
|
|
$due = $applyto.parent('td').parent().first().find('td.plugin_do_date');
|
|
}
|
|
due = PluginDo.stripTags($due.length ? $due.html() : '');
|
|
}
|
|
if (due !== '') {
|
|
titelNo -= 1;
|
|
}
|
|
var newTitle = PluginDo.getLang('title' + titelNo, assignees.join(', '), due);
|
|
|
|
// is closed?
|
|
if (closedon) {
|
|
newTitle += ' ' + PluginDo.getLang('done', closedon);
|
|
}
|
|
|
|
// who closed it?
|
|
if (closedby || closedby === '') {
|
|
if (closedby === '') closedby = LANG.plugins['do'].by_unknown;
|
|
newTitle += ' ' + PluginDo.getLang('closedby', closedby);
|
|
}
|
|
|
|
// apply the title
|
|
$applyto.attr('title', newTitle);
|
|
},
|
|
|
|
/**
|
|
* get a localized string by name.
|
|
*
|
|
* if a arg is given it replaces %s with arg
|
|
*
|
|
* @return {string} localized text.
|
|
*/
|
|
getLang: function (name, arg1, arg2) {
|
|
var lang = LANG.plugins['do'][name];
|
|
|
|
if (arg1 === null) {
|
|
return lang;
|
|
} else if (arg2 === null) {
|
|
return lang.replace(/%(1\$)?(s|d)/, arg1);
|
|
} else {
|
|
return lang.replace(/%(1\$)?(s|d)/, arg1)
|
|
.replace(/%(2\$)?(s|d)/, arg2);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Escapes html entities from a string.
|
|
*/
|
|
hsc: function (text) {
|
|
return text
|
|
.replace('&', '&')
|
|
.replace('<', '<')
|
|
.replace('>', '>')
|
|
.replace('"', '"');
|
|
},
|
|
|
|
/**
|
|
* Removes tags from string
|
|
*
|
|
* @param {string} text
|
|
* @returns {string} untagged text
|
|
*/
|
|
stripTags: function (text) {
|
|
return text.replace(/(<([^>]+)>)/ig, "");
|
|
},
|
|
|
|
/**
|
|
* Determine if a element is late
|
|
*
|
|
* @param {HTMLElement} ele span with due date
|
|
* @returns {boolean} whether task is still open and exceed due date
|
|
*/
|
|
isLate: function (ele) {
|
|
if (typeof ele.parentNode == 'undefined') {
|
|
return false;
|
|
}
|
|
var $ele = jQuery(ele);
|
|
|
|
if ($ele.parent().parent().hasClass('plugin_do_done')) {
|
|
return false;
|
|
}
|
|
var currentdate = new Date(),
|
|
duedate = new Date($ele.html());
|
|
|
|
return duedate.getTime() < currentdate.getTime();
|
|
},
|
|
|
|
/**
|
|
* Returns value of requested url parameter
|
|
*
|
|
* @param {string} url
|
|
* @param {string} keyname
|
|
* @returns {*}
|
|
*/
|
|
urlParam: function (url, keyname) {
|
|
var results = new RegExp('[\\?&]' + keyname + '=([^&#]*)').exec(url);
|
|
if (results === null) {
|
|
return null;
|
|
} else {
|
|
return results[1] || 0;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Update statistics in the page task status view
|
|
*
|
|
* done: All tasks done
|
|
* undone: There are %1$d open tasks
|
|
* late: There are %1$d open tasks, %2$d are late.'
|
|
*
|
|
* @param {string} response result return by ajax toggle request
|
|
* @param {jQuery} $itemspan
|
|
*/
|
|
updatePageTaskView: function (response, $itemspan) {
|
|
var $pagestat = jQuery('.plugin__do_pagetasks');
|
|
if ($pagestat.length > 0) {
|
|
var count = parseInt($pagestat.children().first().html(), 10),
|
|
latecount = 0,
|
|
newClass,
|
|
oldClass = $pagestat.children().first().attr('class'),
|
|
$cdate = $itemspan.find('span.plugin_do_meta_date');
|
|
|
|
if (response) {
|
|
// task is marked done
|
|
if (count == 1) {
|
|
newClass = 'do_done';
|
|
} else if (oldClass != 'do_late') {
|
|
newClass = 'do_undone';
|
|
} else {
|
|
newClass = 'do_undone';
|
|
jQuery('.plugin_do_meta_date')
|
|
.each(function (i, doitem) {
|
|
if (PluginDo.isLate(doitem)) {
|
|
newClass = 'do_late';
|
|
latecount++;
|
|
}
|
|
});
|
|
}
|
|
count -= 1;
|
|
} else {
|
|
//task is marked undone
|
|
if (count === 0) {
|
|
if ($cdate.length && PluginDo.isLate($cdate[0])) {
|
|
newClass = 'do_late';
|
|
latecount++;
|
|
} else {
|
|
newClass = 'do_undone';
|
|
}
|
|
} else {
|
|
newClass = 'do_undone';
|
|
jQuery('.plugin_do_meta_date')
|
|
.each(function (i, doitem) {
|
|
if (PluginDo.isLate(doitem)) {
|
|
newClass = 'do_late';
|
|
latecount++;
|
|
}
|
|
});
|
|
}
|
|
count += 1;
|
|
}
|
|
|
|
var title = PluginDo.getLang('title_' + newClass.substr(3), count, latecount);
|
|
|
|
$pagestat
|
|
.attr('title', title)
|
|
.children().first()
|
|
.html(count)
|
|
.removeClass().addClass(newClass);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Save the task change to wiki and update the html in the page
|
|
*
|
|
* @param {HTMLElement} me clicked url element
|
|
*/
|
|
save_update_SingleTask: function (me) {
|
|
var $me = jQuery(me),
|
|
$itemspan = $me.parent(),
|
|
md5v = $itemspan.attr('class').match(/plugin_do_([a-f0-9]{32})/)[1],
|
|
$dotags = jQuery('.plugin_do_' + md5v),
|
|
|
|
done = $itemspan.hasClass('plugin_do_done'),
|
|
param = {
|
|
call: 'plugin_do',
|
|
do_page: decodeURIComponent(PluginDo.urlParam(me.search.substring(1), 'do_page')),
|
|
do_md5: decodeURIComponent(PluginDo.urlParam(me.search.substring(1), 'do_md5')),
|
|
do_commit: jQuery('#do__popup_msg').val()
|
|
};
|
|
|
|
if (!done) {
|
|
var commitmsg = PluginDo.hsc(param.do_commit);
|
|
//update table(s)
|
|
$dotags.parent('td').parent().find('td.plugin_do_commit').html(commitmsg ? commitmsg : '');
|
|
//update task (inclusive duplicates)
|
|
commitmsg = (commitmsg ? ' (' + PluginDo.getLang("note_done") + commitmsg + ')' : '');
|
|
$dotags.find('span.plugin_do_commit').html(commitmsg);
|
|
} else {
|
|
$dotags.parent('td').parent().find('td.plugin_do_commit').html('');
|
|
$dotags.find('span.plugin_do_commit').html('');
|
|
}
|
|
|
|
var $image = $me.find('img');
|
|
var donr = !$image.is("img[src*='undone.png']");
|
|
$image.attr('src', DOKU_BASE + 'lib/images/throbber.gif');
|
|
|
|
/**
|
|
* callback to update task when it is toggled
|
|
* @param response
|
|
*/
|
|
var updateSingleTask = function (response) {
|
|
var closedby = null,
|
|
closedon = null;
|
|
if (response == "-1" || response == "-2") {
|
|
var langkey = 'notallowed';
|
|
if (response == "-1") {
|
|
langkey = "notloggedin";
|
|
}
|
|
alert(PluginDo.getLang(langkey));
|
|
|
|
//remove throbber
|
|
PluginDo.switchDoNr(!donr, $me);
|
|
return;
|
|
}
|
|
if (response) {
|
|
$dotags.addClass('plugin_do_done');
|
|
if (JSINFO.plugin_do_user_name) {
|
|
$dotags.parent('td').parent().find('td.plugin_do_status span span').html(JSINFO.plugin_do_user_name);
|
|
}
|
|
|
|
closedby = JSINFO.plugin_do_user_clean;
|
|
closedon = response;
|
|
} else {
|
|
$dotags.removeClass('plugin_do_done');
|
|
$dotags.parent('td').parent().find('td.plugin_do_status span span').html(' ');
|
|
}
|
|
PluginDo.switchDoNr(donr, $dotags);
|
|
PluginDo.buildTitle($dotags, [], '', closedby, closedon);
|
|
|
|
//update statistics in the page task status view
|
|
PluginDo.updatePageTaskView(response, $itemspan);
|
|
};
|
|
|
|
//save changes, ajax returns data to mark fail or success
|
|
jQuery.ajax({
|
|
type: "POST",
|
|
url: DOKU_BASE + 'lib/exe/ajax.php',
|
|
data: param,
|
|
success: updateSingleTask,
|
|
dataType: 'json'
|
|
});
|
|
},
|
|
|
|
/**
|
|
* callback which updates do's in the page
|
|
* so that task changes after last page render are displayed correctly
|
|
*
|
|
* @param {Array} doStates ajax response with info from sqlite about tasks in this page
|
|
*/
|
|
updateItems: function (doStates) {
|
|
|
|
jQuery.each(doStates, function (i, state) {
|
|
var $dotags = jQuery('.plugin_do_' + state.md5);
|
|
|
|
PluginDo.buildTitle($dotags, [], '', state.closedby, state.status);
|
|
PluginDo.switchDoNr(!state.status, $dotags);
|
|
if (state.status) {
|
|
$dotags.addClass('plugin_do_done');
|
|
}
|
|
|
|
if (state.msg) {
|
|
var msg = PluginDo.hsc(state.msg);
|
|
$dotags.find('span.plugin_do_commit').html(' (' + PluginDo.getLang("note_done") + msg + ')');
|
|
}
|
|
});
|
|
},
|
|
|
|
/********************************************
|
|
* Toolbar functions *
|
|
********************************************/
|
|
|
|
old_select: null,
|
|
$toolbardialog: null,
|
|
textarea: null,
|
|
|
|
initDialog: function (edid) {
|
|
PluginDo.textarea = jQuery('#' + edid)[0];
|
|
|
|
var fieldsetcontent = '';
|
|
jQuery.each(['assign', 'date'], function (i, input) {
|
|
fieldsetcontent +=
|
|
'<p>' +
|
|
'<label for="do__popup_' + input + '">' +
|
|
LANG.plugins['do']['popup_' + input] +
|
|
'</label>' +
|
|
'<input class="edit" id="do__popup_' + input + '" />' +
|
|
'</p>';
|
|
});
|
|
|
|
// prepare hidden overlay
|
|
PluginDo.$toolbardialog = PluginDo.createOverlay(
|
|
LANG.plugins['do'].popup_title,
|
|
'do__popup',
|
|
fieldsetcontent,
|
|
LANG.plugins['do'].popup_submit,
|
|
PluginDo.insertDoSyntax
|
|
);
|
|
|
|
jQuery('#do__popup_date').datepicker({
|
|
dateFormat: "yy-mm-dd",
|
|
changeMonth: true,
|
|
changeYear: true
|
|
});
|
|
|
|
// if the bureaucracy plugin is installed, use its user autocompletion
|
|
jQuery('#do__popup_assign').addClass('userspicker');
|
|
},
|
|
|
|
toggleToolbarDialog: function (e) {
|
|
PluginDo.old_select = DWgetSelection(PluginDo.textarea);
|
|
var $popup_date = jQuery('#do__popup_date');
|
|
var $popup_assign = jQuery('#do__popup_assign');
|
|
|
|
//check if a task was selected and load it's data
|
|
var txt = PluginDo.old_select.getText();
|
|
$popup_date.val('');
|
|
$popup_assign.val('');
|
|
var m = txt.match(/<do ([^>]*)>[\s\S]*<\/do>/);
|
|
if (m) {
|
|
var users = m[1];
|
|
m = users.match(/\d\d\d\d-\d\d-\d\d/);
|
|
if (m) {
|
|
var date = m[0];
|
|
users = users.replace(date, '');
|
|
$popup_date.val(date);
|
|
}
|
|
users = users.replace(/^\s+/, '');
|
|
users = users.replace(/\s+$/, '');
|
|
$popup_assign.val(users);
|
|
}
|
|
|
|
PluginDo.$toolbardialog.css({
|
|
'position': 'absolute',
|
|
'top': (e.pageY + 10) + 'px',
|
|
'left': (e.pageX - 100) + 'px'
|
|
});
|
|
return PluginDo.$toolbardialog.toggle();
|
|
},
|
|
|
|
/**
|
|
* The submit action of toolbar dialog
|
|
*/
|
|
insertDoSyntax: function () {
|
|
// Validate data
|
|
var $popup_date = jQuery('#do__popup_date');
|
|
var $popup_assign = jQuery('#do__popup_assign');
|
|
|
|
var pre = '<do';
|
|
if ($popup_date.val() && $popup_date.val().match(/^[0-9]{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])/)) {
|
|
pre += ' ' + $popup_date.val();
|
|
}
|
|
if ($popup_assign.val()) {
|
|
pre += ' ' + $popup_assign.val();
|
|
}
|
|
pre += '>';
|
|
|
|
var sel = DWgetSelection(PluginDo.textarea);
|
|
if (sel.start === 0 && sel.end === 0) sel = PluginDo.old_select;
|
|
|
|
var stxt = sel.getText();
|
|
|
|
//strip any previous do tags
|
|
var m = stxt.match(/<do ([^>]*)>[\s\S]*<\/do>/);
|
|
if (m) {
|
|
// we have previous tags, replace them
|
|
stxt = stxt.replace(/<do ([^>]*)>/, pre);
|
|
} else {
|
|
// no selection or previous tags, add them
|
|
stxt = pre + stxt + '</do>';
|
|
}
|
|
|
|
pasteText(sel, stxt);
|
|
$popup_date.val('');
|
|
$popup_assign.val('');
|
|
}
|
|
};
|