Comments on ruiz's Scripts

82 comments

Comment on muxtape + twitter love made Sep 28, 2008:

GeekShadow

Work great with OpenTape !

Comment on GMail - GTD Tickler made Sep 25, 2008:

Derek C

It would probably help if I had a better understanding of how Gmail, Gcal, and Google Apps worked. It would also be easier if I knew how to code javascript, but still I've made the most progress towards making the tickler Gapps-friendly.

I think the problem is how the script recognizes times and dates through the Gapps interface in comparison to the Gmail interface. I'm still getting the "tickle me error - invalid date or time" message.

Also, when I click on "Edit Event Details" in the Gmail tickler, it opens up the popup window and fills the title and the description, but the dates range from ??/??/???? to ??/??/????, regardless of what date I entered in the original tickler bubble.

Any ideas?

Comment on GMail - GTD Tickler made Sep 25, 2008:

Derek C

Okay, I've made some progress in 5 minutes. At the links for schema.google.com/g, replace the "g" with "apps" and it will give you another error.

Now it's telling me "tickle me error; invalid date or time."

At least it's communicating now. It just can't understand anything. I really want this to work with Google Apps.

Comment on GMail - GTD Tickler made Sep 25, 2008:

Derek C

For some reason, I need to have the tickler installed for Gmail Addons to work right. I'm trying to adapt it to Google Apps, but I'm having some difficulties.

Edit Event Details works so far, but Remind Me doesn't work so you always have to do it the long way. Anybody know what schemas.google.com is, and if it differs between regular Google accounts and Google Apps accounts? I think that's the only issue right now.

Here's the semi-fix for Google Apps users:

// ==UserScript==

// @name GMail - GTD Tickler

// @author Martin Ruiz

// @namespace Martin Ruiz

// @description Very Simple Ticker file functionality to GMail/GTDGMail using GCal

// @include http://mail.google.com/*

// @include https://mail.google.com/*

// ==/UserScript==

/*

Author: Martin Ruiz

Credits:

- I adapted code from a lot of other scripts on userscripts... lost track:)

Features:

+ Adds 'Tickle me' link for each message in message view.

+ Custom Popup for Quick Add and link to 'edit event details>>'

+ ';' shortcut key to popup 'Tickle Me' box.

+ Quickly add 'When' you want to be reminded, just like GCal QuickAdd - otherwise -

+ Opens and Fills out GCal Template in separate window with link to original message.

+ Link in GCal reminder will open GMail message in a seperate window.

Tips:

+ Choose the color 'red' or some other bold color so that it clearly stands out.

+ Make your goals calendar public and have your friends track your goals too.

Bonus:

+ Also works with Drafts - In round about way. Draft and email, save, leave draft,

come back to draft, then 'Tickle Me'

- Catch: only works with keyboard shortcut because 'Tickle Me' link does not appear

with draft.

Todo:

+ Add 'Tickle Me' link when new msgs in thread appear.

+ When not in GMail - The highlighted text and current link are included in GCal details

Testing:

+ Works with Firefox 2.0 for PC with Greasemonkey

Version History:

2.5 - 05.05.2008 - merge bug fixes by cbg3

2.4 - 03.26.2007 - Fix date issues

2.3 - 11.12.2007 - Fixed for New GMail

2.2 - 10.29.2007 - Bug fix - default reminders not being set

2.1 - 10.23.2007 - Bug fix - disable shortcut in text areas

2.0 - 09.01.2007 - Rewrite

+ Shortcut

+ Quick Add

*/

(function() {

var gmail;

var DEBUG = false;

var p = null;

var Window;

var Document;

window.addEventListener('load', function() {

if (unsafeWindow.gmonkey) {

unsafeWindow.gmonkey.load('1.0', main);

}

}, true);

function main(g) {

gmail = g;

gmail.registerViewChangeCallback(runGTDTickler);

Document = gmail.getNavPaneElement().ownerDocument;

Window = Document.defaultView;

p = new Prompt();

setupShortcut();

runGTDTickler();

}

function runGTDTickler() {

if (gmail.getActiveViewType() != 'cv') return;

//gmail.getActiveViewElement().addEventListener("DOMNodeInserted", function() { insertDelegateLinks() }, false);

insertDelegateLinks();

}

function setupShortcut() // keyboard shortcut: ";"

{

Window.addEventListener('keyup', function(e) {

if (e.altKey || e.ctrlKey || e.metaKey) {

return false;

}

if (e.keyCode!=59) return;

if (p.isEditing()) return;

var element;

if(e.target) element=e.target;

else if(e.srcElement) element=e.srcElement;

if(element.nodeType==3) element=element.parentNode;

if(element.tagName == 'INPUT' ||

element.tagName == 'TEXTAREA') return;

if (e.keyCode==59) delegate();

}, true);

}

function addReminder(title,when,content) {

when = parseWhen(when);

gcalHttpRequestUnauthorized({

method: 'GET',

url: 'https://www.google.com/calendar/hosted/yourdomain.com/compose?ctext=myevent%20' + when,

onComplete: function(detail) {

var txt = detail.responseText;

txt = txt.replace(/while\(1\)\;/ig,'');

log(txt);

var dates = eval('('+txt+')');

var enddate;

var startdate;

var date;

var from = dates[0][4];

var to = dates[0][5];

if (noDate(from) && noDate(to) ) {

alert('Tickle Me Error. Invalid date or time');

return;

}

// some heuristics...

if ( noDate(to) ) {

date = from;

log("no to date");

} else if ( noDate(from) ) {

date = to;

log("no from date");

} else if ( containsToday(when) ) {

date = from;

log("contains today");

} else if ( containsTomorrow(when) ) {

date = from;

log("contains tomorrow");

} else if ( containsDay(when) && !containsMonth(when) ) {//mon vs month

date = from;

log("contains day but not month");

} else if ( containsNext(when) ) {

date = from;

log("contains next");

} else if ( !isToday(from)) {

date = from;

log(from+' != '+today());

log("from != today");

} else {

date = to;

log("default date = to");

}

if (containsTime(when)) {

startdate = enddate = formatDate(date)+formatTime(date);

} else {

startdate = formatDate(date);

}

log(startdate+' - '+enddate);

addEvent(title, content, startdate, enddate);

},

onError: function(detail) {

alert('Tickle Me Error. Invalid date or time.');

}

});

}

function addEvent(title, content, startdate, enddate) {

var data=

"<entry>"+

" <category>"+

" <title>"+title+"</title>"+

(content?("<content>"+content+"</content>"):"")+

" <gd:transparency>"+

" "+

" <gd:eventstatus>"+

" "+

" <gd:when><gd:reminder>"+

"";

log(data);

gcalHttpRequestAuthorized({

method: 'POST',

url: "https://www.google.com/calendar/hosted/yourdomain.com/feeds/default/private/full",

data: data

});

}

function gcalHttpRequestAuthorized(params) {

gcalHttpRequestUnauthorized({

method: 'POST',

data: '',

url: "http://www.google.com/calendar/hosted/yourdomain.com/render",

onComplete: function (detail) {

var token;

try {

detail.responseHeaders.match(/CAL=([^;]+)/);

token= RegExp.$1;

if (!params.headers) params['headers'] = {};

params['headers']['Authorization'] = "GoogleLogin auth="+token;

gcalHttpRequestUnauthorized(params);

} catch (e) {}

if (!token) { alert('You may not be logged into GCal. Try again later.'); return;}

},

onError: function (detail) {

alert('Tickle Me Error. You may not be logged into GCal.');

}

});

}

function gcalHttpRequestUnauthorized(params) {

log('params\n'+requestToString(params)+'/params');

var r = {headers:{}};

r.method = params.method;

r.headers = (params.headers?params.headers:{});

r.headers["Content-Type"] = "application/atom+xml";

if (params.data) {

r.headers['Content-length'] = params.data.length;

r.data = params.data;

} else {

r.headers['Content-length'] = 0;

}

r.url = params.url;

r.onload = function(detail) {

if (detail.status == 200 || detail.status == 201) {

if(params.onComplete) params.onComplete(detail);

} else {

if (params.onError) params.onError(detail);

error("HTTP request failed2", detail);

}

}

r.onerror = function(detail) {

if (params.onError) params.onError(detail);

error("HTTP request failed", detail);

}



log('req\n'+requestToString(r)+'/req');

GM_xmlhttpRequest(r);

}

function requestToString(r) {

var s='';

for (var i in r) {

s = s + i + ": "+

(i=='headers'?requestToString(r[i]):r[i]) + "\n";

}

return s;

}

function parseWhen(when) {

var w = String(when);

// support 'tomorrow' shortcut 'tom'

w = w.replace(/^tom$/ig,"tomorrow");

if (containsNext(w)) {

if (!containsDay(w)) {

// support 'next' instead of one

w = w.replace(/next/ig,'one');

}

}

return w;

}

function get2Digits(x) {

return (x<10>
}

function today() {

var date = "yyyymmdd";

var d = new Date();



date = date.replace(/yyyy/i, d.getFullYear());

date = date.replace(/mm/i, get2Digits(d.getMonth()+1));

date = date.replace(/dd/i, get2Digits(d.getDate()));

log('today is '+date);

return date;

}

function isToday(d) { return (d==today()); }

function noDate(date) {return (date.search(/^\?/ig) > -1);}

function containsMonth(when) {return (when.search(/month/ig) > -1);}

function containsTomorrow(when) {return (when.search(/tomorrow/ig) > -1);}

function containsToday(when) {return (when.search(/(tod(ay)?)|(now)/ig) > -1);}

function containsNext(when) {return (when.search(/next/ig) > -1);}

function containsTime(when) {return (when.search(/\d{1,2}((pm|am)|(:\d{2}(am|pm)))/ig) > -1);}

function containsDay(when) {return (when.search(/(mon(day)?)|(tue(sday)?)|(wed(nesday)?)|(thu(rsday)?)|(fri(day)?)|(sat(urday)?)|(sun(day)?)/ig) > -1);}

function formatTime(date) {

var s = 'T00:00:00.000';//Z

if (date.length>8) {

s = 'T'+

date.substr(9,2)+':'+

date.substr(11,2)+':'+

date.substr(13,2)+'.000';//Z

}



return s;

}

function formatDate(date) {

var s = date.substr(0,4)+'-'+

date.substr(4,2)+'-'+

date.substr(6,2);

return s;

}

function containsTime(when) {

var t = /\d{1,2}((pm|am)|(:\d{2}(am|pm)))/ig;

return (when.search(t)>-1);

}

function log(x) {

if (!DEBUG) return;

GM_log(x);

return;

if (unsafeWindow.console) {

unsafeWindow.console.log.apply(unsafeWindow.console,

Array.slice(arguments));

}

}

function error(x,d) { log(x+"\n"+d.responseText); };

function askWhen(callback) {

p.show(callback);

return;

var when = prompt("When? eg. tomorrow, next week, friday at 4pm");

if (callback && when != null) callback(when);

}

function editReminderDetails(url) {

var nwin = Window.open(url,"Tickle Me",'height=470,width=600,scrollbars=yes,menubar=no,toolbar=no,status=no');

if (nwin.focus) {nwin.focus();}

}

function processReminder(when, title, gmail_url, event_details_url) {

if (when) {

addReminder(title, when, gmail_url);

return;

}

if (when == null) return; // cancelled --- 'blank' is Okay, open event details

editReminderDetails(event_details_url);

}

function delegate()

{

var url = String(Window.top.location);

var real_id = url.match(/#(.*)?\/(.*)/)[2];

var title = Window.frames.content.document.title; var t=title;

title = escape(t);

//var gmail_url = 'http://mail.google.com/a/yourdomain.com/mail/?source=navclient-ff#inbox/'+real_id;

var gmail_url = "http://mail.google.com/a/yourdomain.commail/?tf=1&fs=1&source=atom&view=cv&search=all&th=" + real_id;

var event_details_url = "http://www.google.com/calendar/hosted/yourdomain.com/event?action=TEMPLATE&text=" + title + "&details=" + escape(gmail_url);

gmail_url = gmail_url.replace(/\&/ig,'&'); // replace ampersands



askWhen(function(when) { processReminder(when, t, gmail_url, event_details_url); });

}

function insertDelegateLinks() {

var msgs = getMessages();

var msg_count = msgs.length;

for(var id=0; id < msg_count; id++) {

var msg = msgs[id];

if(!Document.getElementById("remindme_" + id)) {

var footerLink = document.createElement('div');

footerLink.className = "X5Xvu";

footerLink.setAttribute("style","float: left;");

footerLink.id = "remindme_" + id;

footerLink.addEventListener("click",delegate,false);



footerLink.innerHTML = 'Tickle Me';



msg.appendChild(footerLink);

}

}

}

// customized popup window

function Prompt()

{

var box = Document.getElementById('tickler_prompt');

if (box) { p.show(); return this; }

var self = this;

this.callback = null;



box = Document.createElement('div');

box.setAttribute('id','tickler_prompt');

box.style.zIndex = '101';

var overlay = Document.createElement('div');

box.appendChild(overlay);

overlay.setAttribute('style','display: none;position: fixed;width: 100%;height: 100%;top: 0px;left: 0px;background: #FFFFFF;filter: alpha(opacity=50);-moz-opacity: 0.5;opacity: 0.5;');

var container = Document.createElement('div');

box.appendChild(container);

container.setAttribute('style','display: none;position: fixed;width: 100%;height: 100%;top: 0px;left: 0px;background: transparent;');

var inner = Document.createElement('div');

container.appendChild(inner);

inner.setAttribute('style','display: block;width: 325px;height: 131px;margin: 120px auto 0 auto;background: #FFFFFF;text-align: center;border: 2px solid rgb(171, 171, 171); -moz-border-radius: 25px;');

inner.innerHTML=

'

'+

'
'+

''+

'
'+

'
'+

'
'+

'<table><tbody>'+

'<tr><td>
</td>'+

'<td>When?</td>'+

'<td>'+

'<input />'+

'</td>'+

'<td>
</td>'+

'</tr>'+

'<tr><td></td><td></td>'+

'<td>e.g., tomorrow, next week, friday at 5pm</td>'+

'<td></td></tr>'+

'<tr><td></td><td></td>'+

'<td><input />'+

' '+ //need space

'<label>edit event details »</label>'+

'</td>'+

'<td></td></tr>'+

'</tbody></table>'+

'
';

this.box = box;

this.overlay = overlay;

this.container = container;

this.inner = inner;

this.isEditing = function() { return (this.box.style.display=='');}

this.hide = function() { this.box.style.display = this.overlay.style.display = this.container.style.display= 'none';}

this.show = function(callback) {

this.callback = callback;

var when = Document.getElementById('tickler_when');

this.box.style.display = this.overlay.style.display = this.container.style.display= '';

when.value = '';

when.focus();

}

this.hide();

Document.body.appendChild(box);



// close button

Document.getElementById('tickler_close_btn').addEventListener("mousedown", function() { self.hide();}, false);

// ok button - book reminder in gcal

Document.getElementById('tickler_btn').addEventListener("click",

function() {

self.hide();

var when = Document.getElementById('tickler_when').value;

if(when) self.callback(when);

}, false);

// goto to gcal details

Document.getElementById('tickler_edit_details').addEventListener("mousedown",

function() {

self.hide();

self.callback("");

}, false);

// escape key

//Document.getElementById('tickler_when').addEventListener("blur", function(e) { self.hide(); }, false);

// enter and submit

Document.getElementById('tickler_when').addEventListener("keydown",

function(e) {

if (e.keyCode == 27) self.hide();

}, false);

Document.getElementById('tickler_when').addEventListener("keyup",

function(e) {

if (e.keyCode == 13) {

self.hide();

self.callback((e.target.value.length>0?e.target.value:null));

}

}, false);

}

function getMessages()

{

var msgs = [];

try {

var iterator = gmail.getActiveViewElement().ownerDocument.evaluate(

".//td[contains(concat(' ', @class, ' '), ' bEgJye ')]",

gmail.getActiveViewElement(),

null,

XPathResult.ORDERED_NODE_ITERATOR_TYPE,

null);

} catch(e) { return null; }

for (var msg = iterator.iterateNext(); msg; msg = iterator.iterateNext()) {

msgs.push(msg);

}

return msgs;

}

})();

----------

Comment if you're able to get it to work perfectly, and I'll do the same if I beat you to it.</gd:reminder>

Comment on GMail Real Estate (Minimize Header, Nav or Ads) made Aug 21, 2008:

Innovign

Ruiz, really does free up quite a bit of space - I was surprised =) very nice! and keyboard shortcuts would be a great add-on for show/hide

JD

Comment on GMail Real Estate (Minimize Header, Nav or Ads) made Jul 8, 2008:

Saibot

Ruiz,

Thanks for the update. Unfortunately the message area isn't maximized when the navlinks and/or ads are hidden. Running FF3/GM 0.8.20080609.0.

Also, I wonder if you could add customizable keyboard shortcuts to show/hide as Yooskeh did with the Calendar version.

Comment on GMail Real Estate (Minimize Header, Nav or Ads) made Jul 3, 2008:

Ronnen

great job ruiz !

Is there an option to hide the right and the left buttons, and disable their functionality?

meaning, to stay only with the up-button?

(the right button breaks other script that I'm using, instead of a full screen view, I see a blank right column on the right side on every message)

Thanks,

Ron

Comment on GMail - GTD Tickler made May 11, 2008:

veganjay

Please disregard my previous comment - I did not realize GCal has default reminders!

Google Calendar -> Settings -> Calendars -> Notifications -> Event Reminders -> default

This is working great now! Thanks!

Comment on GMail - GTD Tickler made May 11, 2008:

veganjay

Nice add-on! I've been looking for something like this. Would it be possible to add a check-box for "Reminder" on the initial pop-up instead of going to "Edit event details"?

Thanks!

Comment on GMail - GTD Tickler made May 8, 2008:

Tim Nikolaev

And also would be great if we could use this with Google Apps.

Thanks for a great tool.

Comment on GMail - GTD Tickler made May 6, 2008:

emptyowe

It would be great if the initial popup allowed one to select which calendar to post into. Or if one could specify the default calendar to post tickles to.

Comment on GMail - GTD Tickler made May 5, 2008:

Britonius

Thanks Ruiz. I look forward to your findings on testing FF3b5. I would also love to see this work with the GreaseKit Simbl plugin for Safari on Mac. Know how to do that or know a Mac script dev who could help make it compatible for the Safari browser as well?

Comment on GMail - GTD Tickler made May 5, 2008:

ruiz

@cbg3 thanks for the bug fixes. I've merged them into the script. We all appreciate you looking at it.

Comment on GMail - GTD Tickler made May 4, 2008:

cbg3

Firebug says that containsMonth is undefined. This seems to prevent the script from adding anything to Google Calendar. But once the containsMonth function is added, the script works. (BTW, the definition of Tuesday in the containsDay function needs to be tweaked from (tue(day)?) to (tue(sday)?)

Comment on GMail - GTD Tickler made May 3, 2008:

ruiz

I've never tested with FF3b5. I'll try it.

Comment on GMail - GTD Tickler made May 1, 2008:

Britonius

I added this to Firefox 3b5 and I am not seeing anything. I also use Folders4Gmail, GmailAgenda & Goolge Account Multi-Login. I have also tried this in Safari via the GreaseKit plugin and still nothing.

Comment on GMail - GTD Tickler made Apr 2, 2008:

Big Jon Roberts

I want to second Nathan Sudds - request - it would be great if this worked with Google Apps email accounts as well.

Comment on GMail Real Estate (Minimize Header, Nav or Ads) made Mar 26, 2008:

ruiz

@searchforsun... definitely would have to mod the script for that. What parts of the header would you want to keep?

Comment on GCal Productivity Chain + ToDo List made Mar 26, 2008:

ruiz

@bobielawlintine depends. you must append '!chain' for the todo to be a 'productivity chain'. Otherwise, it will just be a regular todo that's gets done once.

Comment on GMail - GTD Tickler made Mar 26, 2008:

ruiz

@MySaturdaySelf just fixed some of the date issues.

Comment on GCal Productivity Chain + ToDo List made Mar 24, 2008:

bobielawlintine

Sorry, see after each chain entry 'chain' - is that a bug??? how to remove - coolcool!

Comment on GMail - GTD Tickler made Mar 23, 2008:

MySaturdaySelf

The script does not recognize the date now. I don't know why. Before it works ok, now it only accepts tomorrow as date. Any other dates listed in the Gcal quick add don't work.

Comment on GMail - GTD Tickler made Mar 17, 2008:

ruiz

@Kate2174 Will try:)

Comment on GMail - GTD Tickler made Mar 16, 2008:

Kate2174

This is EXACTLY the tool I've been searching for, but I'm having the same problem from my private domain Google Apps Gmail as "Master Scott" (see 03/16/08 posting below). Hopefully, this can be resolved soon. Thanks!

Comment on GMail - GTD Tickler made Mar 16, 2008:

Master Scott

I read the previous post about this, but am unclear as to the solution, or if there is one.

I'm using this in my custom domain Google Apps Gmail account. When I click the 'Tickle Me' link, it works like a charm, but, it defaults back to my @gmail.com calendar, not the @mydomain.com Gmail/cal account that I am sending from. Is this fixable on my end? If not, I'd like to request it. Thanks

FYI: My account does have Gmail 2 new features enabled. I have GTDInbox installed.