EnstylerJS

MyDealz Enstyler Frontend and enhanced features

目前为 2016-11-07 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name EnstylerJS
  3. // @namespace Enstyler
  4. // @description MyDealz Enstyler Frontend and enhanced features
  5. // @include http://www.mydealz.de/*
  6. // @include https://www.mydealz.de/*
  7. // @version 2.11.075
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_log
  11. // @grant GM_xmlhttpRequest
  12. // @require http://code.jquery.com/jquery-3.1.1.min.js
  13. // @require http://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.min.js
  14. // @require http://openuserjs.org/src/libs/sizzle/GM_config.js
  15. // ==/UserScript==
  16.  
  17. // ========== RUN EnstylerJS =====================================
  18. // create object for enstyler "Menu Button"
  19.  
  20. var enUserLogin = false;
  21.  
  22. function EnstylerInit () {
  23. // hide Enstyler2 CSS (c) text because we have a button now
  24. addStyleString('.threadWidget-footer::after {display: none !important};');
  25. EnstylerButtonCreate();
  26. // basic config panel formatting, everything else is formatted by enstyler
  27. var enCSS = ['#GM_config {left: 5% !iportant; top: 9% !important; height: auto !important; max-width: 35em !important;}',
  28. '#GM_config input, #GM_config button { border: 1px solid; margin: 0.5em 0em 0.2em 1em; padding: 0.1em;}',
  29. '#GM_config .reset { font-size: 9pt; padding-right: 1em; }',
  30. '#GM_config_enstyler_var:after {content: ". <- please install actual CSS!"; font-weight: bold;}',
  31. ].join(" ");
  32. addStyleString(enCSS);
  33. enUserLogin = $('.avatar--type-nav').length;
  34. }
  35.  
  36.  
  37. // show popup user info while click on avatar ... ==============
  38. function EnstylerAvatarPopup() {
  39. // if logged in ...
  40. if (enUserLogin) {
  41. // code used for MyDealz avatar popup, thanks to mydealz :-)
  42. var enPopupUser = ['<button data-handler="track popover" data-track="{&quot;action&quot;:&quot;show_short_user_profile&quot;,&quot;label&quot;:&quot;engagement&quot;}"data-popover="{&quot;endpoint&quot;:&quot;',
  43. '/short&quot;,&quot;target&quot;:&quot;#template-popoverLoader&quot;,&quot;layout&quot;:[{&quot;preset&quot;:&quot;e&quot;,&quot;y&quot;:&quot;50%&quot;,&quot;left&quot;:{&quot;offset&quot;:0},&quot;width&quot;:300,&quot;maxWidth&quot;:&quot;100%&quot;}]}">',
  44. '</button>',
  45. ];
  46. // remove second image from cardview
  47. if (GM_config.get('enConfUser')) { addStyleString('.thread-footer-cell a img.avatar.vAlign--all-m.space--mr-1.thread-avatar {display: none;}'); }
  48.  
  49. // replace every avatar link without popup
  50. if (GM_config.get('enConfUser')) {
  51. $('.thread-footer-cell a.user.linkPlain, .user.linkPlain.thread-user').each(function () {
  52. var Iam = $(this);
  53. // get inner html and link to user profile
  54. var myHtml = Iam.html();
  55. var mysrc = Iam.attr('href');
  56. // seperate user name from image and add class user
  57. var myAvatar1 = myHtml.replace(/<span.*/,'');
  58. var myAvatar2 = myHtml.replace(/.*<span class=".* space--mr-1">/,'<span class=" space--mr-1 user link-plain">');
  59.  
  60. // show small / medium sized Avatar
  61. myAvatar1 = myAvatar1.replace('avatar--type-s','avatar--type-m'); //in Dealz
  62. if (GM_config.get('enConfAvatar')) { myAvatar1 = myAvatar1.replace('thread-avatar','avatar--type-m'); }
  63. // compose popup
  64. var myPopup = enPopupUser[0] + Iam.attr('href') + enPopupUser[1] + myAvatar1 + enPopupUser[2] + '<a href="' + Iam.attr('href') + '">'+ myAvatar2 + '</a>';
  65. Iam.replaceWith(myPopup);
  66. });
  67. }
  68. }
  69. }
  70.  
  71.  
  72.  
  73.  
  74.  
  75. function EnstylerStart () {
  76. // ============ stuff to modify page content =============================
  77.  
  78. // REGEX to detect external URL
  79. var REGEX_THREAD = /^https?:\/\/www\.mydealz\.de\/visit\/thread(image)?\/\d+$/;
  80. var REGEX_DESC = /^https?:\/\/www\.mydealz\.de\/visit\/threaddesc\/\d+\/\d+$/;
  81. var REGEX_COMMENT = /^https?:\/\/www\.mydealz\.de\/visit\/comment\/\d+\/\d+$/;
  82. var REGEX_AMAZONMOB = /^https?:\/\/www\.amazon\..*\/gp\/aw\/.*$/;
  83. //var REGEX_AMAZON = /^https?:\/\/www\.amazon\..*$/;
  84.  
  85. //* GM_xmlhhtpREquest not supported by firefox mobile :-(((
  86. // abfangen aller links mit jQuery
  87. $('a').bind('click', function(){
  88. var url = this.href;
  89.  
  90. // externer Link mit Redirect ...
  91. // Match REDIRECT URLs and open new Window with finalUrl
  92. if (GM_config.get('enConfFilterLink') && url.match(REGEX_THREAD) || url.match(REGEX_DESC) || url.match(REGEX_COMMENT)) {
  93. // Workaround: pre open window because of popup blockers
  94. var asyncWindow = window.open(url, '_blank');
  95. // now lookup redirecd external URL ...
  96. // alert("external URL detected");
  97. GM_xmlhttpRequest({
  98. method: 'GET',
  99. url: url,
  100. // here we get the final URL from redirect
  101. onload: function (response) {
  102. // process final URL
  103. var newUrl = response.finalUrl;
  104. //alert(newUrl);
  105. // lets see ...
  106. if (newUrl.match(REGEX_AMAZONMOB)) {
  107. newUrl = newUrl.replace("/gp/aw/d/", "/dp/");
  108. newUrl = newUrl.replace("/gp/aw/ol/", "/gp/offer-listing/");
  109. //alert("Amazon rewritten URL: " + newUrl);
  110. }
  111. // load processed URL in preopened window
  112. asyncWindow.location = newUrl;
  113. }
  114. });
  115. // return without link processing by Browser
  116. return false;
  117. }
  118. // return with link processing in Browser
  119. return true;
  120. }); // - END GM_xmlhttpRequest */
  121. } // END EnstylerStart
  122.  
  123.  
  124.  
  125. // add actions to tread overview @ some places ==================================
  126. function EnstylerDealActions() {
  127. // if logged in ...
  128. if (enUserLogin) {
  129. // code used for MyDealz Dealz actions, thanks to mydealz :-)
  130. var myOuterHtml = [ '<span class="js-options bg--em bRad--a space--h-3 space--v-3 space--mt-3 text--b">', '</span>'];
  131. var enDealAction = [ '<a class="link ico ico--pos-l ico--type-comment-blue space--mr-3"', // comment 0+1
  132. 'href="<ENSTYLER-HREF-HERE>#comment-form" data-handler="track" data-track="{&quot;action&quot;:&quot;scroll_to_comment_add_form&quot;,&quot;label&quot;:&quot;engagement&quot;}">Sag was dazu</a>',
  133. '<a class="link text--color-blue ico ico--type-bookmark-blue ico--pos-l space--mr-3"', //un-bookmark 2+3
  134. 'data-handler="track replace" data-replace="{&quot;endpoint&quot;:&quot;https:\/\/www.mydealz.de\/threads\/<ENSTYLER-THREADID-HERE>/remove&quot;,&quot;method&quot;:&quot;post&quot;}" data-track="{&quot;action&quot;:&quot;save_thread&quot;,&quot;label&quot;:&quot;engagement&quot;}"> Von Liste entfernen</a>',
  135. '<a class="link text--color-blue ico ico--type-pencil-blue ico--pos-l space--mr-3"', // edit 4+5
  136. 'href="<ENSTYLER-HREF-HERE>/edit" data-handler="track" data-track="{&quot;action&quot;:&quot;goto_thread_edit_form&quot;,&quot;beacon&quot;:true}">Bearbeiten</a>',
  137. '<a class="thread-expire link ico ico--type-clock-blue ico--pos-l space--mr-3"', // expiried not working :-(
  138. 'href="<ENSTYLER-HREF-HERE>/expire/report" rel="nofollow" data-handler="track replace" data-track="{&quot;action&quot;:&quot;report_expired_thread&quot;,&quot;label&quot;:&quot;contribution&quot;}" data-replace="{&quot;endpoint&quot;:&quot;https:\/\/www.mydealz.de\/<ENSTYLER-HREF-HERE>/expire\/report&quot;}">Abgelaufen?</a>',
  139. ];
  140. var PATTERN = [ /<ENSTYLER-HREF-HERE>/g, // pattern to replace by deal link ...
  141. /<ENSTYLER-THREADID-HERE>/g, // pattern to replace ID
  142. ]
  143. if (GM_config.get('enConfMoreDeal')) {
  144. var parser = location; // parse location
  145. var pathname = parser.pathname;
  146. var username = pathname.replace(/.*profile\//,'');
  147. username = username.replace(/\/.*/,'');
  148. // no username ??
  149. if (username == "") {
  150. username = "unknown";
  151. } else {
  152. pathname = pathname.replace(username + '/',''); // remove username if path is longer
  153. }
  154. //alert("username:" + username + " pfadname:" +pathname)
  155. // default for all Dealz: comment
  156. var myAction = enDealAction[0]+ enDealAction[1];
  157.  
  158. // Action for special locations only ===========
  159. // saved Dealz panel
  160. if (pathname.endsWith('profile/saved-deals') ){
  161. // add for user saved-dealz: un-bookmark
  162. myAction += enDealAction[2]+ enDealAction[3];
  163. }
  164. if (pathname.endsWith('profile/diskussion') || pathname.endsWith(username)){
  165. // add user dealz and discussions: comment edit
  166. myAction += enDealAction[4]+ enDealAction[5];
  167. }
  168.  
  169. // we have an Action to add to an Deal!
  170. if (myAction != "") {
  171. //GM_log('Action:' + myAction);
  172. // every thread on thread page ...
  173. $('article').each(function () {
  174. // get ThreadID, Link to Deal and DealID
  175. var myThread = $(this).attr('id');
  176. if (!myThread.startsWith('thread_')) {return;}
  177. var myDealHref = $('#' + myThread + ' .thread-title a').attr('href');
  178. var myDealID = myThread.replace('thread_','')
  179. if (myThread.startsWith('To be')) {return;}
  180. // compose final HTML
  181. var newHtml= myOuterHtml[0] + myAction + myOuterHtml[1];
  182. newHtml = newHtml.replace(PATTERN[0], myDealHref);
  183. newHtml = newHtml.replace(PATTERN[1], myDealID);
  184. // append HTML to Deal
  185. $('#' + myThread +' .thread-infoRow').each(function () {
  186. $(this).append(newHtml);
  187. $(this).removeClass('thread-infoRow');
  188. });
  189. });
  190. }
  191. // actions for everywhere ===========
  192. // remove unwanted HTML from deal description
  193. $('.thread--type-detail .userHtml').each(function () {
  194. // userhtml code from mydalz, need to find jafascript to save automatically :-(
  195. var enUserhtml = ['<div class="userHtml overflow--wrap-break space--t-3" data-handler="lightbox-xhr" data-lightbox-xhr="{&quot;name&quot;:&quot;threads&quot;}">',
  196. '</div>', // sourround deal description
  197. ];
  198. // get inner html
  199. var myHtml = $(this).html();
  200.  
  201. // remove unwanted Stuff: combined <div><br><br> stuff, created by cut'npaste html
  202. // not elegant, but works ...
  203. var newHtml = myHtml.replace(/<div>|<div><br>|<\/br>|<\/div>/gi,'');
  204. newHtml = newHtml.replace(/<br><br><br>|<br><br><br><br>|<br><br><br><br><br>/gi,'<br><br>');
  205. // replace original with modifyed html
  206. $(this).replaceWith(enUserhtml[0] + newHtml + enUserhtml[1]);
  207. });
  208.  
  209. } // END enabled
  210. }
  211. }
  212.  
  213.  
  214. // show popup user info while click on avatar ... ======================
  215. function EnstylerAvatarPopup() {
  216. // if logged in ...
  217. if (enUserLogin) {
  218. // code used for MyDealz avatar popup, thanks to mydealz :-)
  219. var enPopupUser = ['<button data-handler="track popover" data-track="{&quot;action&quot;:&quot;show_short_user_profile&quot;,&quot;label&quot;:&quot;engagement&quot;}"data-popover="{&quot;endpoint&quot;:&quot;',
  220. '/short&quot;,&quot;target&quot;:&quot;#template-popoverLoader&quot;,&quot;layout&quot;:[{&quot;preset&quot;:&quot;e&quot;,&quot;y&quot;:&quot;50%&quot;,&quot;left&quot;:{&quot;offset&quot;:0},&quot;width&quot;:300,&quot;maxWidth&quot;:&quot;100%&quot;}]}">',
  221. '</button>',
  222. ];
  223. // remove second image from cardview
  224. if (GM_config.get('enConfUser')) { addStyleString('.thread-footer-cell a img.avatar.vAlign--all-m.space--mr-1.thread-avatar {display: none;}'); }
  225.  
  226. // replace every avatar link without popup
  227. if (GM_config.get('enConfUser')) {
  228. $('.thread-footer-cell a.user.linkPlain, .user.linkPlain.thread-user').each(function () {
  229. var Iam = $(this);
  230. // get inner html and link to user profile
  231. var myHtml = Iam.html();
  232. var mysrc = Iam.attr('href');
  233. // seperate user name from image and add class user
  234. var myAvatar1 = myHtml.replace(/<span.*/,'');
  235. var myAvatar2 = myHtml.replace(/.*<span class=".* space--mr-1">/,'<span class=" space--mr-1 user link-plain">');
  236.  
  237. // show small / medium sized Avatar
  238. myAvatar1 = myAvatar1.replace('avatar--type-s','avatar--type-m'); //in Dealz
  239. if (GM_config.get('enConfAvatar')) { myAvatar1 = myAvatar1.replace('thread-avatar','avatar--type-m'); }
  240. // compose popup
  241. var myPopup = enPopupUser[0] + Iam.attr('href') + enPopupUser[1] + myAvatar1 + enPopupUser[2] + '<a href="' + Iam.attr('href') + '">'+ myAvatar2 + '</a>';
  242. Iam.replaceWith(myPopup);
  243. });
  244. }
  245. }
  246. }
  247.  
  248.  
  249. // create select page or scrollwheel for page navigation =============
  250. var EnstylerPageEnum='enPageEnum';
  251. var selectList = document.createElement("select");
  252. selectList.id = EnstylerPageEnum;
  253. selectList.onchange = EnstylerPageAction;
  254.  
  255. function EnstylerPagePickerCreate() {
  256. // if enabled
  257. if (GM_config.get('enConfPagePicker')) {
  258. // init values and clear select list
  259. var page=1;
  260. var min=1;
  261. var max=1;
  262. $(selectList).empty();
  263. // get page and max from pagenav
  264. if ( $('.text--color-charcoalTint').length ) {
  265. // remove linebreaks
  266. pageHtml = $('.text--color-charcoalTint').html().replace(/\r?\n|\r/g);
  267. //locate actual page and last page
  268. page = pageHtml.replace( /.*>Seite /i ,''); page = page.replace( /<.*/i , '');
  269. max = pageHtml.replace( /.*page=/ ,''); max = max.replace( /[^0-9].*/i , '');
  270. }
  271.  
  272. // alert('min: ' + min + ' max: ' + max + ' page: ' + page)
  273. // create page select element
  274. var x; var last; var option;
  275. for (x = min; x <= max; ) {
  276. option = document.createElement("option");
  277. option.text = x;
  278. selectList.add(option);
  279. last = x;
  280. // non linear increment
  281. var diff = Math.abs(x-page);
  282.  
  283. if ( x < 10 || diff < 5) { x++; }
  284. else if ( x < 1000 && diff > 600) { x += Math.floor(diff/100); }
  285. else { x += Math.floor(diff/2); }
  286. }
  287. // add last page
  288. if (page > max) { max=page;}
  289. if (last < max ) {
  290. option = document.createElement("option");
  291. option.text = max;
  292. selectList.add(option);
  293. }
  294. // set default value
  295. selectList.value = page;
  296. // Set attribite fro Mainnav
  297. selectList.setAttribute('class', 'js-navDropDown-messages vAlign--all-m');
  298. if (GM_config.get('enConfBtn')) {
  299. // Place Picker in subnav
  300. selectList.setAttribute('class', 'box--all-i subNavMenu-link subNavMenu-btn');
  301. $('.subNav-label:last').before(selectList);
  302. } else {
  303. //place picker in MainNav
  304. if ($('.test-loginButton').length) {
  305. $('.test-loginButton').before(selectList);
  306. } else {
  307. $('.js-navDropDown-messages').before(selectList);
  308. }
  309. }
  310. }
  311. }
  312.  
  313. // goto selected Page
  314. function EnstylerPageAction() {
  315. var enPage = 'page=' + $(this).val();
  316. var enUrl = window.location.href;
  317.  
  318. // remove page= and everthing behind
  319. enUrl = enUrl.replace( /page=.*|#.*/ ,'');
  320. // add new page parameter
  321. if ( enUrl.endsWith('?') || enUrl.endsWith('&')) {
  322. enUrl += enPage;
  323. } else {
  324. enUrl += '?'+enPage;
  325. }
  326. // add #thread-comments for deal
  327. if (path.startsWith('/deals/')) { enUrl += '#thread-comments';}
  328. //alert( 'Seite: '+ enPage + ' URL: ' +enUrl );
  329. window.location = enUrl;
  330. }
  331.  
  332.  
  333.  
  334. function EnstylerPagePickerRemove() {
  335. // Removes pagepicker from the document
  336. $('#'+ EnstylerPageEnum).remove();
  337. }
  338.  
  339.  
  340. // create button for display Config ==============
  341. var EnstylerButton = 'EnstylerButton';
  342.  
  343. //var input = document.createElement('a');
  344. // input.setAttribute('href', 'showEnstylerConfig()');
  345. // input.setAttribute('id', EnstylerButton);
  346. var input = document.createElement('input');
  347. input.type = 'button';
  348. input.value = 'Enstyler';
  349. input.setAttribute('id', EnstylerButton)
  350. input.onclick = showEnstylerConfig;
  351.  
  352. function EnstylerButtonCreate() {
  353. // add Enstyler Button to ...
  354. var myElement;
  355. if (GM_config.get('enConfBtn') && $(window).width() > GM_config.get('enConfBtnMinWidth')) {
  356. // add button to MainNav
  357. var Elements = document.getElementsByClassName("nav-link");
  358. myElement = Elements[3];
  359. input.setAttribute('class', 'vAlign--all-m nav-link-text');
  360. input.setAttribute('style', '');
  361. } else {
  362. // add button to SubNav
  363. myElement = document.getElementById('tour-filter');
  364. input.setAttribute('class', 'box--all-i subNavMenu-link');
  365. input.setAttribute('style', 'font-size: 1.28571em; font-weight: 700; top: 3px; left: -0.7em');
  366. }
  367. // only if myElement exist
  368. if (myElement !== null) {
  369. myElement.appendChild(input);
  370. //insertAfter(input, myElement);
  371. }
  372. }
  373.  
  374. function EnstylerButtonRemove() {
  375. // Removes button from the document
  376. $('#'+ EnstylerButton).remove();
  377. }
  378.  
  379.  
  380.  
  381. // ============= GM_config functions =======================================
  382.  
  383. // define GM_config elements
  384. var fieldDefs = {
  385. // Part one: load external content --------
  386. 'enstyler': {
  387. 'section': ['additonal features for Enstyler', ''],
  388. 'label': 'Install / Update CSS...', // Appears on the button
  389. 'type': 'button', // Makes this setting a button input
  390. 'click': function() { // Function to call when button is clicked
  391. showUrl('https://userstyles.org/styles/128262#style-info'); }
  392. },
  393.  
  394. 'dontCookies': {
  395. 'label': 'Mozilla no cookies...', // Appears on the button
  396. 'type': 'button', // Makes this setting a button input
  397. 'click': function() { // Function to call when button is clicked
  398. showUrl('https://addons.mozilla.org/de/addon/i-dont-care-about-cookies/'); }
  399. },
  400.  
  401. //* thhis has to be the last one,display only if internal version is disabled
  402. 'externalMobileRedirect': {
  403. 'label': 'Amazon mobile redirect...', // Appears on the button
  404. 'type': 'button', // Makes this setting a button input
  405. 'click': function() { // Function to call when button is clicked
  406. showUrl('https://greasyfork.org/de/scripts/19700'); }
  407. }, // */
  408.  
  409. // part two: EnstylerJS internal configuration options ------
  410. 'hidden1': { // display next section, dont kow why ...
  411. 'section': ['Configuration', ''],
  412. 'type': 'hidden', // Makes this setting a hidden input
  413. 'value': 'Some hidden value' // Value stored
  414. },
  415.  
  416. // postion of enstyler "button"
  417. 'enConfBtn': {
  418. 'label': 'Show Enstyler in MainNav', // Appears next to field
  419. 'type': 'checkbox', // Makes this setting a checkbox input
  420. 'default': false // Default value if user doesn't change it
  421. },
  422. 'enConfBtnMinWidth': {
  423. 'label': 'only if width is bigger than ', // Appears next to field
  424. 'type': 'int', // Makes this setting a text input
  425. 'min': 600, // Optional lower range limit
  426. 'max': 1200, // Optional upper range limit
  427. 'size': 4, // Limit length of input (default is 25)
  428. 'default': 850 // Default value if user doesn't change it
  429. },
  430.  
  431. // ehanced USerInfo
  432. 'enConfUser': {
  433. 'label': 'Show Popuop Userinfo', // Appears next to field
  434. 'type': 'checkbox', // Makes this setting a checkbox input
  435. 'default': true // Default value if user doesn't change it
  436. },
  437. 'enConfAvatar': {
  438. 'label': 'bigger Avatar for Popuop', // Appears next to field
  439. 'type': 'checkbox', // Makes this setting a checkbox input
  440. 'default': true // Default value if user doesn't change it
  441. },
  442. // enable filtering of external links
  443. 'enConfFilterLink': {
  444. 'label': 'Amazon mobile redirect', // Appears next to field
  445. 'type': 'checkbox', // Makes this setting a checkbox input
  446. 'default': true // Default value if user doesn't change it
  447. }, // */
  448.  
  449. // more Deal actions
  450. 'enConfMoreDeal': {
  451. 'label': 'additional Deal actions', // Appears next to field
  452. 'type': 'checkbox', // Makes this setting a checkbox input
  453. 'default': true // Default value if user doesn't change it
  454. },
  455.  
  456. // Page picker
  457. 'enConfPagePicker': {
  458. 'label': 'Enable Page Picker', // Appears next to field
  459. 'type': 'checkbox', // Makes this setting a checkbox input
  460. 'default': false // Default value if user doesn't change it
  461. },
  462. // display copy message at end of section ...
  463. 'copy': {
  464. 'section': ['', '(c) Gnadelwartz - <a target="blank" href="https://www.mydealz.de/diskussion/enstyler2-style-your-mydealz-incl-pepper-sites-736219">Enstyler2 - Style your MyDealz</a>'],
  465. 'type': 'hidden', // Makes this setting a hidden input
  466. 'value': 'Some hidden value' // Value stored
  467. },
  468. };
  469.  
  470.  
  471. // display GM_copnfig as div, so we cam apply CSS!!
  472. var enGMOptChange = false;
  473. var enGMFrame = document.createElement('div');
  474. document.body.appendChild(enGMFrame);
  475.  
  476. GM_config.init(
  477. {
  478. id: 'GM_config',
  479. title: 'EnstylerJS - Settings',
  480. fields: fieldDefs,
  481. 'events': // Callback functions object
  482. {
  483. //'init': function() { alert('onInit()'); },
  484. // remove elements ich switch is checked or not
  485. 'open': function() {
  486. var enRemoveConfig = [
  487. { check: true, switch: 'enConfFilterLink', remove: 'externalMobileRedirect'},
  488. { check: false, switch: 'enConfBtn', remove: 'enConfBtnMinWidth'},
  489. { check: false, switch: 'enConfUser', remove: 'enConfAvatar'},
  490. { check: false, switch: 'enConfBlackEnable', remove: 'enConfWhitelist'},
  491. { check: false, switch: 'enConfBlackEnable', remove: 'enConfBlacklist'},
  492. ];
  493. $(enRemoveConfig).each(function() {
  494. if (GM_config.get(this.switch) == this.check) {
  495. GM_config.fields[this.remove].remove();
  496. }
  497. });
  498. },
  499. //'reset': function() { enGMOptChange = true; },
  500. // relaod page on close after save
  501. 'save': function() {
  502. EnstylerButtonRemove();
  503. EnstylerButtonCreate();
  504. EnstylerPagePickerRemove();
  505. EnstylerPagePickerCreate();
  506. },
  507. //'close': function() { if (enGMOptChange) { location.reload(); enGMOptChange = false;} },
  508. },
  509. 'frame': enGMFrame // Element used for the panel
  510. }
  511. );
  512.  
  513.  
  514. // EnstylerJS Config Panel anzeigen
  515. function showEnstylerConfig() {
  516. GM_config.open();
  517. }
  518.  
  519. //=========== Support functions for actual use =======
  520.  
  521. // display website in external window
  522. function showUrl(str) {
  523. var myDeco = "innerheight=800,innerwidth=600";
  524. var myName = "enstyler";
  525. // workaround for not working window.focus(): close an existing window first
  526. // not working on mobile :-(
  527. //var myWindowShow = window.open('', myName, "width=100,height=100").close();
  528. var myWindowShow = window.open(str, myName, myDeco);
  529. }
  530.  
  531. // add CSS in to document
  532. function addStyleString(str) {
  533. var node = document.createElement('style');
  534. node.innerHTML = str;
  535. document.body.appendChild(node);
  536. }
  537. // sleep time expects milliseconds, then execute code
  538. // NOTE: code runs in parallel (asnyc)!
  539. // Usage!
  540. // sleepAsync(500).then(() => {
  541. // Do something after the sleep!
  542. // });
  543.  
  544. function sleepAsync (time) {
  545. return new Promise((resolve) => setTimeout(resolve, time));
  546. }
  547.  
  548. // like .insertBefore but as function
  549. function insertAfter(newNode, referenceNode) {
  550. referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
  551. }
  552.  
  553. // ============== START EnstyerJS =============
  554. EnstylerInit();
  555. EnstylerStart();
  556. EnstylerAvatarPopup();
  557. EnstylerDealActions();
  558. EnstylerPagePickerCreate();
  559.  
  560.  
  561. // track DOM change Events, debounce: wait 500ms after mutiple events
  562. // then re-apply (somse) changes to dynamic loaded content,
  563. $('.fGrid-last2, .thread-list--type-card').bind("DOMSubtreeModified",$.debounce( 500, function(){
  564. //GM_log('DOMSubtreeModified detected!!!');
  565. EnstylerDealActions();
  566. EnstylerAvatarPopup();
  567.  
  568. }));
  569.  
  570.