There are 3 previous versions of this script.
// ==UserScript==
// @name Gmail CatsOne integration
// @description Allows posting emails directly from Gmail to CatsOne system
// @author Constantin Bosneaga <ameoba32@gmail.com>
// @version 0.6
// @homepage http://a32.me/2010/07/catsone-gmail-integration-plugin/
// @include http://mail.google.com/*
// @include https://mail.google.com/*
// ==/UserScript==
// CHANGELOG:
// 0.1 2006-01-20 Initial revision
// 0.2 2006-01-20 New CATs function, interface improvements
// 0.3 2006-01-20 Better error handling
// 0.4 2010-08-13 Added more escaping to url params
// 0.5 2010-08-13 Moveable main window
// 0.6 2010-08-13 Catsone API change fix
var searchTimer;
var doc;
var _document = document;
var subdomain = "__CHANGE__ME"
var ctsDialog;
// Loaded message params
var msgFrom;
var msgSubject;
var msgText;
function xpath(query, object) {
if (!object) var object = document;
return document.evaluate(query, object, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
}
function debug(msg) {
if (console) console.log( msg );
}
function eid(a) {
return _document.getElementById(a);
}
// Check if transaction ID is entered, before making any calls
function checkTransactionID() {
var tmp = GM_getValue("trans_id","");
if (tmp == "") configTransactionId();
}
// Enter transaction ID
function configTransactionId() {
var reply = prompt("Enter CATs transaction ID", GM_getValue("trans_id"));
GM_setValue("trans_id", reply)
}
function isCatsError(response) {
debug("Response code="+response.status);
debug("Response code="+response.statusText);
debug("Response text="+response.responseText);
if (response.status != 200) {
alert("Error: response code != 100." + response.responseText);
return true;
}
// Check if success
if (response.responseText.indexOf('success="true"') == -1) {
alert('Cats call failed.\nResponse: ' + response.responseText);
return true;
}
return false;
}
function uri(str) {
return encodeURIComponent(str);
}
function sendToCats(id, from, subject, text) {
id = eid('catsPerson').getAttribute('person_id');
if (id == "" || id == null) {alert('Choose person');return;}
if (eid('catsText') == "") {alert('No text to send');return;}
var data = "data_type=candidate&id="+id+"&from="+uri(eid('catsFrom').value)+"&subject="+uri(eid('catsSubject').value)+"&message="+uri(eid('catsText').value);
debug("data=" + data);
checkTransactionID();
GM_xmlhttpRequest({
method: 'POST',
url: 'https://'+subdomain+'.catsone.com/api/add_email_activity?transaction_code=' + GM_getValue("trans_id"),
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': 'application/atom+xml,application/xml,text/xml,application/x-httpd-php',
'Content-type': 'application/x-www-form-urlencoded; charset=utf-8;',
},
data: data,
onload: function(responseDetails) {
var error = isCatsError(responseDetails);
if (error) return;
closeDialog();
},
onerror: function(responseDetails) {
alert('Ajax error');
}
});
}
function searchCats() {
var keyword = '*'+document.getElementById('catsSearch').value+'*';
var data = "&keywords="+uri(keyword)+"&data_type=candidate";
debug("Searching cats="+keyword)
debug("data="+data)
checkTransactionID();
debug('https://'+subdomain+'.catsone.com/api/search?transaction_code=' + GM_getValue("trans_id") );
GM_xmlhttpRequest({
method: 'POST',
url: 'https://'+subdomain+'.catsone.com/api/search?transaction_code=' + GM_getValue("trans_id"),
headers: {
'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey',
'Accept': 'application/atom+xml,application/xml,text/xml,application/x-httpd-php',
'Content-type': 'application/x-www-form-urlencoded; charset=utf-8;',
},
data: data,
onload: function(responseDetails) {
var error = isCatsError(responseDetails);
if (error) return;
var text = responseDetails.responseText;
text = text.replace("\n","","g");
// Clear search results
eid('catsSearchResult').innerHTML = '';
// Parse search results list
var rePat1 = new RegExp("<item>(.*?)<\/item>","img");
var item, id, caption;
while (item = rePat1.exec(text)) {
id = /<id>(.*?)<\/id>/.exec(item[1]); id = id[1];
caption = /<summary>(.*?)<\/summary>/.exec(item[1]); caption = caption[1];
var a = _document.createElement('a');
a.addEventListener('click', function(event) {
// Select person
eid('catsPerson').innerHTML = this.innerHTML;
eid('catsPerson').setAttribute('person_id',this.getAttribute('person_id'));
//selectPerson();
},true);
a.setAttribute('href', 'javascript:void(0)');
a.setAttribute('person_id', id);
a.setAttribute('class', 'el ou');
a.innerHTML = caption;
var div = _document.createElement('div');
div.appendChild(a);
eid('catsSearchResult').appendChild( div );
}
//135226
if (eid('catsSearchResult').innerHTML == "")
eid('catsSearchResult').innerHTML = '-none found-';
},
onerror: function(responseDetails) {
alert('Ajax error');
}
});
}
function addButton() {
var tmp = xpath("//div[@class='gB']");
if (tmp.snapshotLength > 0) {
for (var i = 0 ; i < tmp.snapshotLength ; i++) {
var n = tmp.snapshotItem(i).previousSibling;
if (!n) {
var msgid=tmp.snapshotItem(i).parentNode.parentNode.parentNode.parentNode.getAttribute("id");
var c = document.createElement('button');
c.innerHTML = ' Add to CATs';
c.setAttribute('msgid',msgid);
c.addEventListener('click', function(event) {
clickButton(this);
},true);
tmp.snapshotItem(i).parentNode.insertBefore(c, tmp.snapshotItem(i));
}
}
}
}
/**
* Clicks on CATs button
*/
function clickButton(_this) {
// Show dialog
showDialog();
var msg = {id:'', obj:'', body:'', from:'', to:[]};
msg.id = _this.getAttribute("msgid");
msg.obj = xpath("//div[@id='+msg.id+']").snapshotItem(0);
// Message BODY text
tmp = xpath("//div[@class='ii gt']/div", msg.obj);
if(tmp){
msg.body = tmp.snapshotItem(0).innerHTML;
}
// Message FROM
tmp = xpath("//div[@class='gE iv gt']//td[@class='gF gK']//h3[@class='gD']/span", msg.obj);
if (tmp){
msg.from = tmp.snapshotItem(0).getAttribute("email");
}
// Message TO
var tmp = xpath("//div[@class='gE iv gt']//td[@class='gF gK']//span[@class='hb']//span", msg.obj);
if (tmp){
for(var i=0; i< tmp.snapshotLength;i++){
msg.to[i] = tmp.snapshotItem(i).getAttribute("email");
}
}
console.log(msg);
// Parse message
//var message = _this.parentNode.parentNode.innerHTML;
var message = msg.body;
eid('catsFrom').value = msg.from;
eid('catsSearch').value = msg.from;
// Message subject
try {
tmp = xpath("//h1[@class='ha']/span");
eid('catsSubject').value = tmp.snapshotItem(0).innerHTML.trim();
} catch(e) { eid('catsSubject').value = ""; }
// Message text
tmp = _document.getSelection();
if (tmp == '') tmp = message.replace(/(<([^>]+)>)/ig,"")
eid('catsText').value = tmp;
// Message date
//var msgDate = /span.*?title="(.*?)"/.exec(message);
//msgDate = msgDate[1];
//alert(msgDate);
// Message from
//try {
// tmp = /email="(.*?)"/.exec(message);
// eid('catsFrom').value = tmp[1];
// eid('catsSearch').value = tmp[1];
//} catch (e) { eid('catsFrom').value = ""; }
// Perform search at once
window.setTimeout( function(event){searchCats();}, 300);
}
function showDialog() {
var tmp;
// no double open
if (ctsDialog) return;
ctsDialog = document.createElement('div');
var t="", s="";
t += ' <div id="catsTitle" style="padding:5px; height:20px; background-color:#abc;cursor:move;" onmousedown="dragStart(event, \'ctsDialog\');">';
t += ' <span id="CATStitlespan" style="float:left;"><b>Add to CATS</b></span>';
t += ' <span id="dlgCATClose" style="float:right; cursor:hand; cursor:pointer;"><a href="javascript:;" onclick="closeDialog();" class="el ou">Close</a> ×</span>';
t += ' </div>';
t += ' <div id="contentCATS" style="height:340px; padding-top:10px;display:block;">';
t += ' <div style="width:160px; height:300px; float:left;display:table-cell">';
t += ' <div align="left">Search candidate:<br/><input id="catsSearch" style="width:154px;" placeholder="Search person"/></div>';
t += ' <br/>Candidates found:<br/>';
t += ' <div id="catsSearchResult" style="height:219px; width:99%; overflow:auto; margin-top:5px; border:1px solid #ccc;"><i>none found</i></div>';
t += ' </div>';
t += ' <div style="width:350px; height:300px;float: right;display:table-cell;">';
t += ' <table width="100%">';
t += ' <tr><td style="font-weight:bold;">Selected</td><td><div id="catsPerson" style="font-weight:bold;"><span style="font-weight:normal;font-decoration:italic;">No candidate selected</span></div></td></tr>';
t += ' <tr><td style="font-weight:bold;">From:</td><td><input type="text" id="catsFrom" size="30"></td></tr>';
t += ' <tr><td style="font-weight:bold;">Subject:</td><td><input type="text" id="catsSubject" size="30"></td></tr>';
t += ' <tr><td colspan="2"><textarea id="catsText" style="border:1px solid #ccc; height:220px; width:99%;"></textarea></td></tr>';
t += ' </table>';
t += ' </div>';
t += ' <p style="text-align:right;display:block;"><button id="catsButton" style="width:50%;">Submit</button></p>';
t += ' </div>';
s += '\n<script type="text/javascript">';
s += '\n function Browser() {';
s += '\n var ua, s, i;';
s += '\n this.isIE = false;';
s += '\n this.isNS = false;';
s += '\n this.version = null;';
s += '\n ua = navigator.userAgent;';
s += '\n s = "MSIE";';
s += '\n if ((i = ua.indexOf(s)) >= 0) {';
s += '\n this.isIE = true;';
s += '\n this.version = parseFloat(ua.substr(i + s.length));';
s += '\n return;';
s += '\n }';
s += '\n s = "Netscape6/";';
s += '\n if ((i = ua.indexOf(s)) >= 0) {';
s += '\n this.isNS = true;';
s += '\n this.version = parseFloat(ua.substr(i + s.length));';
s += '\n return;';
s += '\n }';
s += '\n';
s += '\n // Treat any other "Gecko" browser as NS 6.1.';
s += '\n s = "Gecko";';
s += '\n if ((i = ua.indexOf(s)) >= 0) {';
s += '\n this.isNS = true;';
s += '\n this.version = 6.1;';
s += '\n return;';
s += '\n }';
s += '\n }';
s += '\n';
s += '\n var browser = new Browser();';
s += '\n';
s += '\n // Global object to hold drag information.';
s += '\n var dragObj = new Object();';
s += '\n dragObj.zIndex = 0;';
s += '\n';
s += '\n function dragStart(event, id) {';
s += '\n';
s += '\n var el;';
s += '\n var x, y;';
s += '\n';
s += '\n // If an element id was given, find it. Otherwise use the element being';
s += '\n // clicked on.';
s += '\n if (id) dragObj.elNode = document.getElementById(id);';
s += '\n else {';
s += '\n if (browser.isIE) dragObj.elNode = window.event.srcElement;';
s += '\n if (browser.isNS) dragObj.elNode = event.target;';
s += '\n';
s += '\n // If this is a text node, use its parent element.';
s += '\n if (dragObj.elNode.nodeType == 3) dragObj.elNode = dragObj.elNode.parentNode;';
s += '\n }';
s += '\n';
s += '\n // Get cursor position with respect to the page.';
s += '\n if (browser.isIE) {';
s += '\n x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;';
s += '\n y = window.event.clientY + document.documentElement.scrollTop + document.body.scrollTop;';
s += '\n }';
s += '\n if (browser.isNS) {';
s += '\n x = event.clientX + window.scrollX;';
s += '\n y = event.clientY + window.scrollY;';
s += '\n }';
s += '\n';
s += '\n // Save starting positions of cursor and element.';
s += '\n dragObj.cursorStartX = x;';
s += '\n dragObj.cursorStartY = y;';
s += '\n dragObj.elStartLeft = parseInt(dragObj.elNode.style.left, 10);';
s += '\n dragObj.elStartTop = parseInt(dragObj.elNode.style.top, 10);';
s += '\n';
s += '\n if (isNaN(dragObj.elStartLeft)) dragObj.elStartLeft = 0;';
s += '\n if (isNaN(dragObj.elStartTop)) dragObj.elStartTop = 0;';
s += '\n';
s += '\n // Update elements z-index.';
s += '\n dragObj.elNode.style.zIndex = ++dragObj.zIndex;';
s += '\n';
s += '\n // Capture mousemove and mouseup events on the page.';
s += '\n if (browser.isIE) {';
s += '\n document.attachEvent("onmousemove", dragGo);';
s += '\n document.attachEvent("onmouseup", dragStop);';
s += '\n window.event.cancelBubble = true;';
s += '\n window.event.returnValue = false;';
s += '\n }';
s += '\n if (browser.isNS) {';
s += '\n document.addEventListener("mousemove", dragGo, true);';
s += '\n document.addEventListener("mouseup", dragStop, true);';
s += '\n event.preventDefault();';
s += '\n }';
s += '\n }';
s += '\n';
s += '\n function dragGo(event) {';
s += '\n';
s += '\n var x, y;';
s += '\n';
s += '\n // Get cursor position with respect to the page.';
s += '\n if (browser.isIE) {';
s += '\n x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;';
s += '\n y = window.event.clientY + document.documentElement.scrollTop + document.body.scrollTop;';
s += '\n }';
s += '\n if (browser.isNS) {';
s += '\n x = event.clientX + window.scrollX;';
s += '\n y = event.clientY + window.scrollY;';
s += '\n }';
s += '\n';
s += '\n // Move drag element by the same amount the cursor has moved.';
s += '\n dragObj.elNode.style.left = (dragObj.elStartLeft + x - dragObj.cursorStartX) + "px";';
s += '\n dragObj.elNode.style.top = (dragObj.elStartTop + y - dragObj.cursorStartY) + "px";';
s += '\n';
s += '\n if (browser.isIE) {';
s += '\n window.event.cancelBubble = true;';
s += '\n window.event.returnValue = false;';
s += '\n }';
s += '\n if (browser.isNS) event.preventDefault();';
s += '\n }';
s += '\n';
s += '\n function dragStop(event) {';
s += '\n';
s += '\n // Stop capturing mousemove and mouseup events.';
s += '\n if (browser.isIE) {';
s += '\n document.detachEvent("onmousemove", dragGo);';
s += '\n document.detachEvent("onmouseup", dragStop);';
s += '\n }';
s += '\n if (browser.isNS) {';
s += '\n document.removeEventListener("mousemove", dragGo, true);';
s += '\n document.removeEventListener("mouseup", dragStop, true);';
s += '\n }';
s += '\n }';
s += '\n</script>';
ctsDialog.innerHTML = t + s;
ctsDialog.style.display='block';
ctsDialog.style.top = window.pageYOffset + 50 + "px";
ctsDialog.style.left = "50px";
ctsDialog.style.height = "380px";
ctsDialog.style.width = "520px";
ctsDialog.style.zIndex = "10";
ctsDialog.style.backgroundColor="#fff";
ctsDialog.style.font="14px Calibri,sans-serif";
ctsDialog.style.border = "3px outset";
ctsDialog.style.position = 'absolute';
ctsDialog.style.padding = '5px';
ctsDialog.setAttribute('id', 'ctsDialog');
document.body.appendChild( ctsDialog );
// Search input
eid('catsSearch').addEventListener('keyup', function(event) {
window.clearTimeout(searchTimer);
searchTimer = window.setTimeout( function(event){searchCats();}, 300);
},true);
// Submit button
eid('catsButton').addEventListener('click', function(event) {
sendToCats();
},true);
// Close button
document.getElementById('dlgCATClose').addEventListener('click', function(event) {
closeDialog();
},true);
}
function closeDialog() {
document.body.removeChild(ctsDialog);
ctsDialog = null;
}
if (document.body) {
window.setInterval(function() {
addButton();
}, 100);
GM_registerMenuCommand("Enter Transaction ID", configTransactionId);
}