GMX standalone window view

Set option to open email in standalone window (gmx / web.de)

  1. // ==UserScript==
  2. // @name GMX standalone window view
  3. // @name:de GMX Standalone-Fensteransicht
  4. // @name:fr GMX email - fenêtre séparée
  5. // @namespace https://github.com/Procyon-b
  6. // @version 0.9.4
  7. // @description Set option to open email in standalone window (gmx / web.de)
  8. // @description:de Stellen Sie die Option so ein, dass E-Mails im eigenständigen Fenster geöffnet werden (gmx / web.de)
  9. // @description:fr Réactiver l'ouverture des emails dans une fenêtre popup (gmx / web.de)
  10. // @author Achernar
  11. // @match https://3c.gmx.net/mail/client/*
  12. // @match https://3c-bap.gmx.net/mail/client/*
  13. // @include https://3c-bs.gmx.tld/mail/client/*
  14. // @match https://3c.web.de/mail/client/*
  15. // @match https://3c-bap.web.de/mail/client/*
  16. // @run-at document-start
  17. // @grant GM_setValue
  18. // @grant GM_getValue
  19. // @grant window.close
  20. // ==/UserScript==
  21.  
  22. (function() {
  23. "use strict";
  24.  
  25. var ML, MLp, R, tb, v=0;
  26.  
  27. if ( /^\/mail\/client\/(home|folder|search|spa\/list|mailSearch)/.test(location.pathname) ) document.addEventListener('DOMContentLoaded', function(){
  28. const maxRetry=100;
  29. var e, r, retry=maxRetry;
  30.  
  31. function toggle(ev) {
  32. if (!e) return;
  33. var v=(typeof ev == 'object')? !phx.vars.enableStandaloneView : ev;
  34. e.checked=v;
  35. if (phx && phx.vars) phx.vars.enableStandaloneView=v;
  36. try{
  37. GM_setValue('option', v);
  38. }catch(er){
  39. window.sessionStorage._popup_=v;
  40. }
  41. }
  42.  
  43. function addChk() {
  44. r=document.querySelector('.widget.menubar .button-container.left, webmailer-mail-list, webmailer-mail-search');
  45.  
  46. var OE;
  47. // new design?
  48. if (r && ['WEBMAILER-MAIL-LIST', 'WEBMAILER-MAIL-SEARCH'].includes(r.nodeName) ) {
  49. R=r;
  50. // do we have style to inject?
  51. if (styles.R) {
  52. addSt(R.shadowRoot, styles.R);
  53. delete styles.R;
  54. }
  55. r=r.shadowRoot.querySelector('list-toolbar');
  56. tb=r;
  57. if (r) r=r.shadowRoot.querySelector('.list-toolbar__left');
  58. }
  59.  
  60. if (!(r)) {
  61. if (retry--) {
  62. setTimeout(addChk,100);
  63. }
  64. return;
  65. }
  66. if (R) {
  67. OE=document.createElement('div');
  68. OE.className=r.firstElementChild.className;
  69. OE.style='order: 9;';
  70. }
  71. retry=maxRetry;
  72. e=document.createElement('input');
  73. e.type='checkbox';
  74. e.id='standaloneView';
  75. e.title='Standalone view';
  76. e.style='margin-top: 6px; order: 9;';
  77. if (OE) OE.appendChild(e);
  78. r.appendChild(OE || e);
  79. e.onclick=toggle;
  80. try{
  81. toggle(GM_getValue('option',true));
  82. }catch(er){
  83. let v=window.sessionStorage._popup_;
  84. if (v === undefined) v=true;
  85. else v=JSON.parse(v);
  86. toggle(v);
  87. }
  88.  
  89. if (window !== top) (document.querySelector('.mail-list__container #mail-head') ||
  90. document.querySelector('webmailer-mail-list') || document).addEventListener('click', function(ev){
  91. if ( (ev.target.id.substr(-10)=='fullscreen') && ev.ctrlKey) {
  92. ev.stopPropagation();
  93. let mId=ev.target.parentNode.querySelector('[href*="mailId"]');
  94. if (mId && /mailId=([^&]+)/.exec(mId)) openW(RegExp.$1);
  95. }
  96. }, true);
  97.  
  98. watchFC();
  99. }
  100.  
  101. addChk();
  102.  
  103. const obs = new MutationObserver(function(mutL){
  104. for (let mut of mutL) {
  105. for (let el of mut.addedNodes) {
  106. if (el.classList && el.classList.contains('menubar')) {
  107. r=document.querySelector('.widget.menubar .button-container.left');
  108. addChk();
  109. return;
  110. }
  111. }
  112. }
  113. });
  114.  
  115. ML=document.querySelector('#panel-mail-table .panel-body form');
  116. if (ML) {
  117. obs.observe(ML, {subtree: false, childList: true, attributes: false} );
  118. }
  119.  
  120. function watchFC() {
  121. // new layout 2023-02
  122. if (R) {
  123. MLp=R.shadowRoot.querySelector('list-mail-list')
  124. ML=MLp.shadowRoot;
  125. }
  126. // previous (other gmx TLDs)
  127. if (!ML) ML=document.querySelector('#panel-mail-table .panel-body form');
  128. ML.addEventListener('click', function(ev){
  129. if (!phx.vars.enableStandaloneView) return;
  130. var tg=ev.target, li;
  131. if (tg.classList.contains('mail-open')
  132. || ( (tg.classList.contains('hoverMenu-icon') || tg.classList.contains('hover-menu-element') ) && ( (li=tg.closest('li')) && li.dataset.oaoHover=='open' ))
  133. || (R && tg.classList.contains('list-mail-item__fullscreen')) ) {
  134. ev.stopPropagation();
  135. let mId=tg.closest('tr[data-oao-mailid]');
  136. let F;
  137. if (mId) mId=mId.attributes['data-oao-mailid'].value;
  138. // design 2023-02
  139. else {
  140. mId=tg.closest('list-mail-item, search-list-item');
  141. if (mId) {
  142. F=mId.querySelector('.list-mail-item__folder');
  143. mId=mId.id;
  144. F=F && F.title && findFol(F.title);
  145. }
  146. }
  147. openW(mId, F);
  148. }
  149. },
  150. {capture: true} );
  151. }
  152.  
  153. function openW(mId, F, TO) {
  154. if (!TO) {
  155. // ensure that it opens a popup and not a tab
  156. setTimeout(function(){openW(mId, F, 1);}, 0);
  157. return;
  158. }
  159. F=F || document.querySelector('.folder.active');
  160. F=F && F.id;
  161. let u=location.origin+location.pathname.replace(/search\/[^;]+;/,'folder;')+'?folderId='+F+'#';
  162. u=location.origin+location.pathname.replace(/(spa\/|mailSearch)[^;]*;/,'home;')+'?folderId='+F+'#';
  163. let w=Math.min( Math.max(1024, ML.scrollWidth || tb.scrollWidth) ,1400);
  164. if (R) mId=mId.replace(/^tmai/, 'id');
  165. window.open(u, 'tmai-'+mId ,'width='+w+',height=600');
  166. }
  167.  
  168. });
  169.  
  170. function findFol(f) {
  171. var r, a=f.split('/');
  172. if (a.length > 1) {
  173. r=document.querySelector('.mail-directory > li[data-webdriver="'+a[0]+'"]');
  174.  
  175. for (let i=1; i < a.length; i++) {
  176. if (r) r=r.querySelector(':scope > ul > li > .folder > a[title^="'+a[i]+'"]');
  177. if (r) r=r.closest('li');
  178. }
  179. if (r) r=r.querySelector(':scope > .folder');
  180. }
  181. else {
  182. r=document.querySelector('.mail-directory > li > .folder > a[title^="'+a[0]+'"]');
  183. if (r) r=r.closest('.folder');
  184. }
  185.  
  186. return r;
  187. }
  188.  
  189. function addSt(r,s,t) {
  190. let st=document.createElement('style');
  191. try{
  192. (r || document.head || document.documentElement).appendChild(st);
  193. st.innerText=s;
  194. }catch(e){
  195. if (t) document.addEventListener('DOMContentLoaded',function(){addSt(r,s);});
  196. else setTimeout(function(){addSt(r,s,t);},0);
  197. }
  198. }
  199.  
  200. var styles={};
  201.  
  202. if (window.name && (window.name.length>=20) && window.name.startsWith('tmai-') ) {
  203. let mId=/^(?:tmai-)?(.*)/.exec(window.name)[1];
  204. let fId=/folderId=([^&]*)/.exec(location.search)[1];
  205. let h='#action/mailDisplay/mailId/'+mId+'/page/0';
  206.  
  207. window.onhashchange=function(){
  208. if (location.href.includes('#') && (location.hash != h) ) location.hash=h;
  209. }
  210.  
  211. if (location.href.includes('#')) {
  212. location.hash='#';
  213. location.hash=h;
  214. }
  215.  
  216. addSt(null, '#navigation, #section-0, .section-1 .prev, .section-1 .next, .section-1 .menubar, .ad, div#mail-instant-reply, #maillist, #selectionCountMessage, webmailer-mail-list .mail-info > ul.icons {display: none !important;} .section-1 {left: 0 !important;} .mail-display-wrapper {top: 0 !important;left: 0 !important;} html.can-have-sky .section-content {margin-right: 0 !important;} .section-1 > .section-container {bottom:0 !important;} div#system-message > div {display: block !important}');
  217. styles={
  218. 'R':':host list-toolbar, :host list-mail-list {display:none;}',
  219. };
  220.  
  221. var retryWSR=300;
  222.  
  223. function showWithSR() {
  224. if (!ML) {
  225. setTimeout(showWithSR, 20);
  226. return;
  227. }
  228. var e=ML.querySelector('list-mail-item#'+mId);
  229. if (!e) {
  230. let a=ML.querySelectorAll('list-mail-item:not(.seen)');
  231. if (a.length) {
  232. a.forEach((e)=>e.classList.add('seen'));
  233. let b=ML.querySelector('list-paging-footer input ~ button');
  234. b.click();
  235. setTimeout(showWithSR, 200);
  236. return;
  237. }
  238. }
  239. if (e) e.click();
  240. else if (--retryWSR) setTimeout(showWithSR, 20);
  241. }
  242.  
  243. function ready() {
  244. // design 2023-02 ?
  245. if (!ML) {
  246. // click() must be set
  247. setTimeout(function(){
  248. document.querySelector('.folder#'+fId+' > .label').click();
  249. showWithSR();
  250. }, 0);
  251. }
  252.  
  253. let c=50;
  254. function setTitle() {
  255. let t=document.querySelector('.section-1 .mail-subject dd');
  256. if (t) {
  257. document.title=document.title.split('-')[0]+' - '+t.innerText;
  258. t=document.querySelectorAll('[id$="fullscreen"]');
  259. // more than one button
  260. for (let i=0; i < t.length; i++) {
  261. t[i].addEventListener('click', function(ev){
  262. ev.stopPropagation();
  263. window.close();
  264. }, {capture: true});
  265. }
  266. let t2=document.querySelector('#mail-detail');
  267. if (t2) t2.focus();
  268. }
  269. else c-- && setTimeout(setTitle, 100);
  270. }
  271. setTitle();
  272. document.body.addEventListener('click', function(ev){
  273. if (ev.target.id=='fullscreen') window.close();
  274. }, {capture: true});
  275.  
  276. // prevent keyboard interaction
  277. document.body.addEventListener('keydown', function(ev){
  278. ev.stopPropagation();
  279. }, true);
  280. }
  281.  
  282. if (document.readyState != 'loading') ready();
  283. else document.addEventListener('DOMContentLoaded', ready);
  284. }
  285.  
  286. // prevent keyboard interaction
  287. if ( /^\/mail\/client\/mailbody\//.test(location.pathname) ) {
  288. function init() {
  289. try {
  290. document.documentElement.addEventListener('keydown', function(ev){ ev.stopPropagation(); }, true);
  291. }catch(e){
  292. document.addEventListener('DOMContentLoaded', init);
  293. }
  294. }
  295. init();
  296. }
  297.  
  298. })();