-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Save timesheet automatically #23
Labels
Comments
Here's the JS from the linked extension which auto-saves every 15 minutes of no activity. The good stuff is at the bottom. var Entry = function(cell, month_year) {
this.init(cell, month_year);
this.enhance();
}
Entry.prototype.init = function(cell, month_year) {
this.cell = cell;
this.month_year = month_year;
this.input = $('input', cell)[0];
this.noteslink = $('a', cell)[0];
this.name = this.input.name;
this.notesinput = document.forms[0][this.name + '_dialog_notes'];
this.fixHTML();
}
Entry.prototype.enhance = function() {
this.addTimer();
this.improveNotes();
this.markToday();
}
Entry.prototype.fixHTML = function() {
var nobr = this.cell;
this.cell = $(this.cell).parent('td');
$(nobr).wrap('<div class="entry-wrapper"></div>');
$(nobr).children().unwrap();
this.cell.addClass('entry-cell');
this.cell = $('.entry-wrapper', this.cell);
$(this.input).attr('autocomplete', 'off');
}
/**
* Adds timer functionality to this entry.
*/
Entry.prototype.addTimer = function() {
if (this.isToday() || this.hasSavedTimer()) {
this.start = $('<a class="start-timer">Start Timer</a>').appendTo(this.cell)
var input = this.input, self = this;
this.start.toggle(function(){
self.startTimer();
$(this).text('Stop Timer');
},
function() {
self.stopTimer();
$(this).text('Start Timer');
});
this.loadTimer();
}
}
Entry.prototype.startTimer = function() {
var input = this.input;
var ref = this;
if (!input.value) { input.value = '0.00'; }
this.timer = setInterval(function(){
ref.input.value = Math.round((parseFloat(ref.input.value) + 0.01) * 100)/100;
$(ref.input).trigger('change').trigger('blur');
ref.timed += 0.01;
}, 36000);
$(this.input).addClass('running-timer');
}
Entry.prototype.stopTimer = function() {
if(this.timer) {
clearInterval(this.timer);
this.timer = false;
this.timed = 0;
}
$(this.input).removeClass('running-timer');
}
Entry.prototype.saveTimer = function(remainder) {
var time = 0;
if (window.is_form_save || remainder) {
var timer = parseFloat(this.input.value);
time = Math.round((timer * 100) % 25) / 100;
if (time >= 0.13) {
time = -(Math.round((0.25 - time) * 100) / 100);
}
} else {
time = this.timed;
}
this.save('timer', time);
}
Entry.prototype.wasPersisted = function() {
return $(this.input).parent('tr').has('font.error').size() > 0;
}
Entry.prototype.loadTimer = function() {
var item = this.load('timer');
if (item) {
var val = Math.round(parseFloat(this.input.value) * 100)/100;
if (isNaN(val)) { val = 0.0; }
added = parseFloat(item);
if (isNaN(added)) { added = 0.0; }
val += added;
this.timed = added;
if (!this.wasPersisted()) {
this.input.value = Math.round(val * 100) / 100;
}
this.start.click();
$(this.input).change();
this.remove('timer');
}
}
Entry.prototype.hasSavedTimer = function() {
return this.load('timer') ? true : false;
}
/**
* Retrieves the notes for a given entry.
*/
Entry.prototype.getNotes = function() {
var message = '';
if (this.notesinput) {
message = this.notesinput.value;
}
return message;
}
/**
* Renders a Notes edit form.
*/
Entry.prototype.improveNotes = function() {
var value = this.getNotes();
var name = this.name + '_dialog_notes';
$(this.noteslink).remove();
var ref = this;
$(this.input).focus(function() {
Entry.closeAllNotes(ref);
if (!ref.haspopover) {
$(ref.input).popover({
html : true,
placement : 'bottom',
trigger : 'manual',
content : function() {
var popover = $('<div class="tooltip-notes" id="' + ref.name + '_notes"></div>');
var text = $('<textarea name="' + ref.name + '_notes_real_input" id="'+ ref.name +'_notes_real_input" placeholder="Note details..."></textarea>');
text.text(ref.getNotes()).appendTo(popover);
text.after('<div class="instructions pull-left"><sub><b>Enter</b> to Save, <b>Esc</b> to Cancel, <b>Shift+Enter</b> for newline.</sub></div>' +
'<div class="popover-group pull-right clearfix">' +
'<button class="save-notes btn btn-primary">Save</button>' +
'<button class="close-notes btn btn-danger">Cancel</button>' +
'</div>');
return popover[0].outerHTML;
},
title : 'Notes',
});
// Show the Popover
$(ref.input).popover('show');
ref.haspopover = true;
// Textarea Bindings
$('#'+ref.name +'_notes_real_input').keyup(function(e){
// Auto-height
while(parseInt($(this).css('height')) <= $(this)[0].scrollHeight ){
$(this)[0].rows++;
}
}).keydown(function(e){ //have to do this in keydown to prevent the enters from being accepted by the text box
// Handle Keys
key = (e.keyCode ? e.keyCode : e.which);
if(key == 13 && !(e.ctrlKey || e.altKey || e.metaKey || e.shiftKey)) { // Enter
e.stopPropagation();
return ref.closeNotes(true);
}else if(key == 27){ // Escape
return ref.closeNotes();
}
}).keyup(); // Call on box display
// Button Bindings
$('.close-notes').click(function() {
return ref.closeNotes();
});
$('.save-notes').click(function(){
return ref.closeNotes(true);
});
}
}).click(function(e){ //make it easier to get the popover back if you accidently close it
$(this).trigger('focus');
});
this.loadNotes();
}
Entry.prototype.closeNotes = function(save, nofocus){
if (save) {
var notes = $('#' + this.name + '_notes_real_input');
if (notes.size()) {
this.notesinput.value = notes.val();
}
}
if (!nofocus) { this.input.focus(); }
$(this.input).popover('destroy');
this.haspopover = false;
return false;
};
Entry.closeAllNotes = function(skip) {
if (window.entries) {
var e = window.entries.length;
while(e--) {
var entry = window.entries[e];
if (skip && entry === skip) {
continue;
}
entry.closeNotes(false, true);
}
}
};
Entry.prototype.saveNotes = function() {
this.save('notes', this.getNotes());
}
Entry.prototype.loadNotes = function() {
var local = this.load('notes');
if (!this.getNotes() && local) {
this.notesinput.value = local;
}
}
Entry.prototype.getTid = function() {
if (!this.tid) {
var search = window.location.search.split(';'),
params = [];
for(var i = 0; i < search.length; i++) {
var exploded = search[i].split('=');
params[exploded[0]] = exploded[1];
}
this.tid = params['timesheet_id'];
}
return this.tid;
}
Entry.prototype.save = function(name, value) {
var tid = this.getTid();
localStorage[tid + '_' + this.name + '_' + name] = value;
}
Entry.prototype.load = function(name) {
var tid = this.getTid();
if (localStorage[tid + '_' + this.name + '_' + name]) {
return localStorage[tid + '_' + this.name + '_' + name];
}
return false;
}
Entry.prototype.remove = function(name) {
var tid = this.getTid();
localStorage.removeItem(tid + '_' + this.name + '_' + name);
}
Entry.prototype.isToday = function() {
if (typeof this.is_today == 'undefined') {
//get our date string for this column
var col = (this.name.split('_'))[1].replace('c', '');
col = (+col) - 3;
var date = parseInt($('.table-header-row td > font').eq(col).text());
var col_date = new Date(this.month_year.join('-') + '-' + date);
var today = new Date();
this.is_today = (today.getDate() == date) && (today.getMonth() == col_date.getMonth()) && (today.getFullYear() == this.month_year[0]);
}
return this.is_today;
}
Entry.prototype.markToday = function() {
if (this.isToday()) {
this.cell.addClass('today');
}
}
// Helper to get the date range for a timesheet
function getTimesheetMonthYear() {
var month_year = document.forms[0]['_date'].value;
return month_year.split('-').slice(0, 2);
}
// ======================== SETUP FUNCTION and EVENTS ================================ //
//If this is the proper timesheet view, create entries
if (window.location.search.indexOf(';action=grid;') > -1) {
var m_y = getTimesheetMonthYear();
var entries = [];
//Create an Entry object for each time entry slot.
$('td nobr', formtable).has('input').has('.notesIcon').removeClass('disabled').each(function(ind, el){
entries.push(new Entry(el, m_y));
});
//add a class to disabled cells for theming
$('td', formtable).has('nobr input').not('.entry-cell').not('.project-cell').addClass('entry-cell disabled');
//save the timesheet timers.
function submitTimesheet(nosubmit) {
//get all our timers that are running
var e = entries.length;
while(e--) {
var entry = entries[e];
if (entry.timer) {
entry.saveTimer();
}
entry.saveNotes();
}
if (!nosubmit) {
$('input[name="_save_grid"]').click();
}
}
$(window).bind('beforeunload', function(e) {
submitTimesheet(true);
});
//allow users to configure autosave
$('.date-row td').append('<div class="autosave-wrapper"><input id="autosave" type="checkbox" /><label for="autosave">AutoSave after 15m of inactivity.</label></div>');
if (typeof(localStorage['autosave']) == 'undefined') {
localStorage['autosave'] = true;
}
//save the form every 15m
time = setTimeout(submitTimesheet, 900000);
var resetTimeout = function() {
clearTimeout(time);
if (localStorage['autosave']) {
time = setTimeout(submitTimesheet, 900000);
}
}
//reset the timeout if the page is in use
$('body').mousemove(function(){
resetTimeout();
});
var check = localStorage['autosave'] && localStorage['autosave'] != 'false';
$('#autosave').prop('checked', check).click(function(e){
localStorage['autosave'] = this.checked;
resetTimeout();
});
} |
crittermike
added a commit
that referenced
this issue
Aug 27, 2015
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This should help with losing data due to getting logged out. Can take inspiration from the code of https://chrome.google.com/webstore/detail/enhanced-openair-timeshee/cndbpehenhdahdpiodadlihdkofcakkm?hl=en which does this (or did).
The text was updated successfully, but these errors were encountered: