PageRenderTime 59ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/healthscreen_gmail_integ/healthscreen_gmail_integ.user.js

https://github.com/arvidj/my-userscripts
JavaScript | 497 lines | 399 code | 64 blank | 34 comment | 41 complexity | 94f670d360e0eafe8726cbb6f35748f4 MD5 | raw file
  1. // ==UserScript==
  2. // @name Healthscreen GMail integration
  3. // @namespace arvid.jakobsson@gmail.com
  4. // @description Integrates GMail clients with healthscreen
  5. // @include https://mail.google.com/mail/*
  6. // @include http://mail.google.com/mail/*
  7. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js
  8. // @require http://plugins.jquery.com/files/jqSOAPClient.js_4.txt
  9. // @require http://plugins.jquery.com/files/jqXMLUtils.js_5.txt
  10. // @require http://pajhome.org.uk/crypt/md5/md5.js
  11. // ==/UserScript==
  12. /*
  13. * gmail: handles gmail specific functions
  14. */
  15. var gmail = {
  16. init: function() {
  17. log("> gmail.init");
  18. this.canvasFrame = $xs("id('canvas_frame')");
  19. log("< gmail.init");
  20. },
  21. getNavPane: function() {
  22. var frameDoc = $x("id('canvas_frame')")[0].contentDocument;
  23. log("gmail.getNavPane, framedoc: %s, url: %s", frameDoc, frameDoc.location.href);
  24. return $xs(".//div[@class='IY0d9c']/div[@class='XoqCub EGSDee' and @style]/div[@class='XoqCub' and div[contains(@class, 'cOSVMd')]]", frameDoc);
  25. },
  26. createNavBar: function(details) {
  27. var navPane = this.getNavPane();
  28. if (!navPane)
  29. throw "createNavBar could not find getNavPane";
  30. var navBarStyle = "background-color: " + details.color + "; margin: 0px 9px 0px 0px; -moz-border-radius: 2px;";
  31. var navBar = create("div", {style: navBarStyle}, navPane);
  32. var title = create("h2", {}, navBar);
  33. title.textContent = details.title || "No title specified";
  34. var expandToggle = create("a", {}, title);;
  35. expandToggle.addEventListener("click", function () {
  36. log("exand/collapse");
  37. }, false);
  38. var content = create("div", {}, navBar);
  39. content.innerHTML = details.content || "No content specified";
  40. },
  41. createSideBar: function (content, sideBarStyle) {
  42. log("> gmail.createSideBar");
  43. content = content || "";
  44. var sideBarDiv = create("div", {'class': 'GM_sideBarElement'});
  45. style(sideBarDiv, sideBarStyle || {});
  46. sideBarDiv.innerHTML = content;
  47. style(sideBarDiv, {cssFloat: 'right', height: '100%', width: '15%'});
  48. this.canvasFrame.parentNode.insertBefore(sideBarDiv, this.canvasFrame.nextSibling);
  49. style(this.canvasFrame, {cssFloat: 'left', height: '100%', width: '85%'});
  50. log("< gmail.createSideBar");
  51. return sideBarDiv;
  52. }
  53. };
  54. /*
  55. * gmhs: GMail - Healtscreen integration
  56. */
  57. var gmhs = {
  58. sidebar: null,
  59. contentDiv: null,
  60. onload: function() {
  61. try {
  62. if (document.location == top.location) { // && location.href == "https://mail.google.com/mail/#inbox") {
  63. log("activating on url", location.href);
  64. this.checkDependencies();
  65. try {
  66. gmail.init();
  67. this.sideBar = gmail.createSideBar(''
  68. + '<div style="margin: 0 10px;">'
  69. + '<h2 class="gmhs-sidebar-title">Sugar</h2>'
  70. + '<div class="gmhs-sidebar-content"></div>'
  71. + '<div class="gmhs-sidebar-controls></div>'
  72. + '</div>'
  73. );
  74. this.contentDiv = this.sideBar.getElementsByClassName('gmhs-sidebar-content')[0];
  75. if (sugar.isLoggedIn()) {
  76. }
  77. else {
  78. var credentials = this.getCredentials();
  79. this.showLoginForm(credentials);
  80. }
  81. }
  82. catch (e) {
  83. log("Exception thrown when creating sidebar element:" + e);
  84. }
  85. }
  86. else
  87. log("not activating on url: %s", location.href);
  88. }
  89. catch (e) {
  90. log("exception thrown gmhs.onlaod");
  91. log(e);
  92. }
  93. },
  94. showLoginForm: function(credentials) {
  95. log("> gmhs.showLoginForm");
  96. this.contentDiv.innerHTML = "<h3>Login</h3>";
  97. credentials = credentials || {username: "", password: "", remember: false};
  98. /*
  99. <form>
  100. <label for="gmhs-username">Username</label><input type="text" name="gmhs-username" value="" />
  101. <label for="gmhs-password">Password</label><input type="text" name="gmhs-password" value="" />
  102. <label for="gmhs-remember">Remember</label><input type="text" name="gmhs-remember" value="" />
  103. <input type="submit" value="login" />
  104. </form>
  105. */
  106. var loginfrm = create('form', {}, this.contentDiv);
  107. var userlbl = create('label', {for: 'gmhs-username'}, loginfrm);
  108. userlbl.textContent = 'Username:';
  109. var userinp = create('input', {type: 'text', name: 'gmhs-username', value: credentials.username}, loginfrm);
  110. var passlbl = create('label', {for: 'gmhs-password'}, loginfrm);
  111. passlbl.textContent = 'Password:';
  112. var passinp = create('input', {type: 'password', name: 'gmhs-password', value: credentials.password}, loginfrm);
  113. var rememberlbl = create('label', {for: 'gmhs-remember'}, loginfrm);
  114. rememberlbl.textContent = 'Remember:';
  115. var rememberinp = create('input', {type: 'checkbox', name: 'gmhs-remember', checked: (credentials.remember ? 'on' : 'off')}, loginfrm);
  116. var submit = create('input', {type: 'submit', name: 'gmhs-submit', value: 'submit'}, loginfrm);
  117. var that = this;
  118. loginfrm.addEventListener('submit', function (ev) {
  119. ev.preventDefault();
  120. ev.stopPropagation();
  121. log("submitting form, logging in");
  122. that.login(userinp.value, passinp.value, rememberinp.value);
  123. }, false);
  124. },
  125. login: function(user, pass, rmb) {
  126. log('logging in: ' + $A(arguments).join(', '));
  127. if (rmb) {
  128. serialize('gmhs-credentials',
  129. {username: user, password: pass, remember: rmb});
  130. }
  131. sugar.login(
  132. user,
  133. pass,
  134. bind(this.onLoginLoad, this),
  135. bind(this.onLoginError, this));
  136. },
  137. onLoginError: function(rd) {
  138. log('something strange occurred when logging in!');
  139. },
  140. onLoginLoad: function(rd) {
  141. log('logged in!');
  142. this.showClients();
  143. },
  144. showClients: function() {
  145. this.contentDiv.innerHTML = '<h3>Clients</h3><ol>' +
  146. '<li>Some client</li>' +
  147. '<li>Some client</li>' +
  148. '<li>Some client</li>' +
  149. '</ol>';
  150. },
  151. getCredentials: function () {
  152. return deserialize("gmhs-credentials");
  153. },
  154. checkDependencies: function () {
  155. if (jQuery)
  156. log("Has jQuery");
  157. else
  158. throw depencyException("jQuery");
  159. if (jQuery.xmlToJSON)
  160. log("has jQuery.xmlToJSON");
  161. else
  162. throw depencyException("jQuery.xmlToJSON");
  163. if (SOAPClient)
  164. log("has SOAPClient");
  165. else
  166. throw depencyException("SOAPClient");
  167. },
  168. depencyException: function(dependency) {
  169. return sprintf('Dependency "\f" missing!', dependency);
  170. }
  171. };
  172. var sugar = {
  173. /* soapUrl: "https://sugar.healthscreen.com/soap.php", */
  174. soapUrl: "http://demo.sugarcrm.com/sugarcrm/soap.php",
  175. sessionId: "",
  176. charSet: "utf-8",
  177. soapEnvelope: {
  178. head: '<?xml version="1.0" encoding="UTF-8"?>'
  179. + '<SOAP-ENV:Envelope '
  180. + 'xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" '
  181. + 'xmlns:ns1="http://www.sugarcrm.com/sugarcrm" '
  182. + 'xmlns:xsd="http://www.w3.org/2001/XMLSchema" '
  183. + 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
  184. + 'xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" '
  185. + 'SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'
  186. + '<SOAP-ENV:Body>',
  187. tail: '</SOAP-ENV:Body></SOAP-ENV:Envelope>',
  188. join: function (body) {
  189. return this.head + body + this.tail;
  190. }
  191. },
  192. initSoapClient: function () {
  193. console.log("> Sugar.initSoapClient");
  194. console.log("< Sugar.initSoapClient");
  195. },
  196. /*
  197. * SOAP-requests
  198. */
  199. login: function (username, password, load, error) {
  200. console.log("> Sugar.login");
  201. var loginbody = '<ns1:login>'
  202. + '<user_auth xsi:type="ns1:user_auth">'
  203. + '<user_name xsi:type="xsd:string">' + username + '</user_name>'
  204. + '<password xsi:type="xsd:string">' + hex_md5(password) + '</password>'
  205. + '<version xsi:type="xsd:string">1</version>'
  206. + '</user_auth>'
  207. + '<application_name xsi:nil="true"/>'
  208. + '</ns1:login>';
  209. this.sendRequest('login', loginbody, load, error);
  210. console.log("< Sugar.login");
  211. },
  212. test: function (testStr, load, error) {
  213. console.log("> Sugar.test");
  214. var body = '<ns1:test><string xsi:type="xsd:string">' + testStr + '</string></ns1:test>';
  215. this.sendRequest('test', body, load, error);
  216. console.log("< Sugar.test");
  217. },
  218. isLoggedIn: function() {
  219. return this.sessionId != "";
  220. },
  221. sendRequest: function(soap_action, body, onload, onerror) {
  222. log(sprintf("sendRequest, action: \f", soap_action));
  223. var data = this.soapEnvelope.join(body);
  224. var proxy = this.soapUrl;
  225. var action = proxy + '/' + soap_action;
  226. GM_xmlhttpRequest({
  227. method: "POST",
  228. url: proxy,
  229. headers: {
  230. "Content-Type": "text/xml; charset=\"\"" + this.charSet + "\"",
  231. "SOAPAction": sprintf('"\f"', action)
  232. },
  233. data: data,
  234. onload: function (rd) {
  235. log("sugar.sendRequest.onload");
  236. if (onload)
  237. onload(rd);
  238. },
  239. onerror: function (rd) {
  240. log("sugar.sendRequest.onerror");
  241. if (onerror)
  242. onerror(rd);
  243. }
  244. });
  245. },
  246. /*
  247. testCallback: function(responseObject) {
  248. console.log("Sugar.testCallback");
  249. console.log(responseObject.toSource());;
  250. },
  251. loginCallback: function(responseObject) {
  252. console.log("Sugar.loginCallback");
  253. console.log(responseObject);
  254. },
  255. */
  256. getContacts: function() {}
  257. };
  258. log("Healthscreen gmail: start");
  259. window.addEventListener("load", bind(gmhs.onload, gmhs), false);
  260. /*
  261. * My standard library :)
  262. */
  263. function style(n, style) {
  264. if (style.constructor == String) {
  265. return n.style[style];
  266. }
  267. else if (style.constructor == Object) {
  268. for (var prop in style)
  269. n.style[prop] = style[prop];
  270. return n;
  271. }
  272. return null;
  273. }
  274. function create(nn, attr, p) {
  275. var n = document.createElement(nn);
  276. for (a in attr)
  277. n.setAttribute(a, attr[a]);
  278. if (p) p.appendChild(n);
  279. return n;
  280. }
  281. function log() {
  282. if (console)
  283. console.log.apply(this, arguments);
  284. else if (GM_log)
  285. GM_log($A(arguments).join(""));
  286. }
  287. fireEvent = function fireEvent(node, type) {
  288. var evt = document.createEvent("Event");
  289. evt.initEvent(type, true, false); // bubble, don't be cancelable
  290. node.dispatchEvent(evt);
  291. };
  292. var tictac = {
  293. now: function () {
  294. return new Date();
  295. },
  296. tic: function() {
  297. this.times = this.times || [];
  298. return this.times.push(new Date());
  299. },
  300. tac: function() {
  301. this.times = this.times || [];
  302. return this.now() - this.times.pop();
  303. }
  304. };
  305. function profile(obj){
  306. var tictac = {
  307. now: function () {
  308. return new Date();
  309. },
  310. tic: function() {
  311. this.times = this.times || [];
  312. return this.times.push(new Date());
  313. },
  314. tac: function() {
  315. this.times = this.times || [];
  316. return this.now() - this.times.pop();
  317. }
  318. };
  319. for (var prop in obj) {
  320. if (obj[prop].constructor == Function) {
  321. console.log("adding profiling for " + prop);
  322. obj["_" + prop] = obj[prop];
  323. obj[prop] = (function(prop) {
  324. return function () {
  325. console.log("profiling " + prop);
  326. tictac.tic();
  327. console.log($A(arguments).join(", "));
  328. obj["_" + prop].apply(obj, arguments);
  329. console.log(prop + ": " + tictac.tac() + " ms");
  330. };
  331. })(prop);
  332. }
  333. }
  334. return obj;
  335. }
  336. function parseRelDate(relDateStr) {
  337. var dateParts = relDateStr.replace("ago", "").trim().split(","), now = (new Date());
  338. for (var i = 0; i < dateParts.length; i++) {
  339. var m = dateParts[i].trim().split(/\W+/);
  340. var value = m[0], unit = m[1];
  341. if (unit.match(/weeks?/)) {
  342. now.setDate(now.getDate() - value*7);
  343. }
  344. else if (unit.match(/days?/)) {
  345. now.setDate(now.getDate() - value);
  346. }
  347. else if (unit.match(/hours?/)) {
  348. now.setHours(now.getHours() - value);
  349. }
  350. else if (unit.match(/minutes?/)) {
  351. now.setMinutes(now.getMinutes() - value);
  352. }
  353. }
  354. return now;
  355. }
  356. function parseIntSort(a,b,asc) {
  357. return sortf(parseInt(a,10), parseInt(b,10), asc);
  358. }
  359. function sortf(a, b, asc) {
  360. if (asc)
  361. return (a-b);
  362. else
  363. return -sortf(a,b, true);
  364. }
  365. function sortstr(a, b, asc) {
  366. if (asc)
  367. return (a > b) ? 1 : -1;
  368. else
  369. return !sortf(a, b, true);
  370. }
  371. function dateSort(a, b, asc) { return sortf(parseRelDate(a), parseRelDate(b), asc); };
  372. function $x(xpath, root) { // From Johan Sundström
  373. var doc = root ? root.evaluate ? root : root.ownerDocument : document, next;
  374. var got = doc.evaluate(xpath, root||doc, null, null, null), result = [];
  375. while((next = got.iterateNext())) {
  376. result.push(next);
  377. }
  378. return result;
  379. }
  380. function $xs(xpath, root) { return $x(xpath, root)[0]; }
  381. String.prototype.trim = function() { return this.replace(/^\W+|\W+$/gi, ""); };
  382. function bind(method, obj) {
  383. return function() {
  384. method.apply(obj, arguments);
  385. };
  386. }
  387. function curry(method, obj) {
  388. var curryargs = $A(arguments).slice(2);
  389. return function() { return method.apply(obj || window, curryargs.concat($A(arguments))); };
  390. }
  391. function $A(arr) {
  392. var r = [], len = arr.length;
  393. while (len--) r.unshift(arr[len]);
  394. return r;
  395. }
  396. function sprintf(str) {
  397. var a;
  398. args = $A(arguments);
  399. args.shift();
  400. while ((a = args.shift()) !== undefined)
  401. str = str.replace("\f", a);
  402. return str;
  403. }
  404. function deserialize(name, def) {
  405. return eval(GM_getValue(name, def) );
  406. }
  407. function serialize(name, val) {
  408. GM_setValue(name, uneval(val));
  409. }