您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
MyDealz Enstyler enhanced features incl. Amazon Mobile Redirect
当前为
// ==UserScript== // @name EnstylerJS // @namespace Enstyler // @description MyDealz Enstyler enhanced features incl. Amazon Mobile Redirect // @include http://www.mydealz.de/* // @include https://www.mydealz.de/* // @include https://userstyles.org/styles/128262/* // @include https://www.amazon.*/gp/aw/* // @version 2.11.302 // @grant GM_getValue // @grant GM_setValue // @grant GM_log // @grant GM_xmlhttpRequest // @require http://code.jquery.com/jquery-3.1.1.min.js // @require http://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.min.js // @require http://openuserjs.org/src/libs/sizzle/GM_config.js // ==/UserScript== // ========== INIT EnstylerJS ===================================== // init Enstyler environment var enUserLogin = false; var enUserName = ''; var enSection = ''; var EnstylerStartTime=Date.now(); // Parse location for later use var enLocParser= location; var DEBUG=false; function EnstylerInit () { // hide Enstyler2 CSS (c) text because we have a button now addStyleString('.threadWidget-footer::after {display: none !important};'); // get LoginStatus and Username if (enUserLogin = $('.avatar--type-nav').length) { enUserName = $('.navDropDown a').attr('href'); enUserName = enUserName.replace(/.*\/profile\/([^\/]+).*/,'$1'); } // get Section (first element in path) enSection= enLocParser.pathname.replace(/\/([^\/]+\/*).*/,'/$1'); } // add actions to tread overview @ some places ================================== // code used for MyDealz Dealz actions, thanks to mydealz :-) var myOuterHtml = [ '<span class="js-options bg--em bRad--a space--h-3 space--v-3 space--mt-3 text--b">', '</span>']; var enDealAction = [ '<a title="Sag was dazu" class="link ico ico--pos-l ico--type-comment-blue space--mr-3"'+ // comment 0+1+3 'href="<ENSTYLER-HREF-HERE>#comment-form" data-handler="track" data-track="{"action":"scroll_to_comment_add_form","label":"engagement"}">', 'Sag was dazu', '', '</a>', '<a title="Von Liste entfernen" class="link text--color-blue ico ico--type-bookmark-blue ico--pos-l space--mr-3"' + //un-bookmark 4+5+7 'data-handler="track replace" data-replace="{"endpoint":"https:\/\/www.mydealz.de\/threads\/<ENSTYLER-THREADID-HERE>/remove","method":"post"}" data-track="{"action":"save_thread","label":"engagement"}">', 'Von Liste entfernen', '', '</a>', '<a title="Bearbeiten" class="link text--color-blue ico ico--type-pencil-blue ico--pos-l space--mr-3"'+ // edit 8+9+11 'href="<ENSTYLER-HREF-HERE>/edit" data-handler="track" data-track="{"action":"goto_thread_edit_form","beacon":true}">', 'Bearbeiten', '', '</a>', '<a title="Abgelaufen?" class="thread-expire link ico ico--type-clock-blue ico--pos-l space--mr-3"'+ // expiried not working :-( 'href="<ENSTYLER-HREF-HERE>/expire/report" rel="nofollow" data-handler="track replace" data-track="{"action":"report_expired_thread","label":"contribution"}" data-replace="{"endpoint":"https:\/\/www.mydealz.de\/<ENSTYLER-HREF-HERE>/expire\/report"}">', 'Abgelaufen?', '', '</a>', ]; var PATTERN = [ /<ENSTYLER-HREF-HERE>/g, // pattern to replace by deal link ... /<ENSTYLER-THREADID-HERE>/g // pattern to replace ID ]; var enDealAdd=''; enDealMarker='thread_' function EnstylerDealActions(){ // use parsed location var pathname = enLocParser.pathname; var myText=0; // no username ?? if (enUserName != "") { pathname = pathname.replace(enUserName + '/',''); // remove username if path is longer } // display short/no text? if ($('.ico--type-grid-subNavActive').length) { myText=1; } // default for all Dealz: comment enDealAdd = enDealAction[0]+ enDealAction[1+myText] + enDealAction[3]; // Action for special locations only =========== // saved Dealz panel if (pathname.endsWith('profile/saved-deals') ){ // add for user saved-dealz: un-bookmark enDealAdd += enDealAction[4]+ enDealAction[5+myText]; + enDealAction[7] } if (pathname.endsWith('profile/diskussion') || pathname.endsWith(enUserName)){ // add user dealz and discussions: comment edit enDealAdd += enDealAction[8]+ enDealAction[9+myText] + enDealAction[11]; } EnstylerDealActionsDo() } function EnstylerDealActionsDo() { // if logged in and enabled ... if (enUserLogin && GM_config.get('enConfMoreDeal')) { // every thread on thread page ... $('article').each(function () { // get ThreadID, Link to Deal and DealID var myThread = $(this).attr('id'); if (!myThread.startsWith(enDealMarker)) {return;} var myDealHref = $('#' + myThread + ' .thread-title a').attr('href'); var myDealID = myThread.replace(enDealMarker,''); if (myThread.startsWith('To be')) {return;} // compose final HTML var newHtml= myOuterHtml[0] + enDealAdd + myOuterHtml[1]; newHtml = newHtml.replace(PATTERN[0], myDealHref); newHtml = newHtml.replace(PATTERN[1], myDealID); // append HTML to Deal $('#' + myThread +' .thread-infoRow').each(function () { $(this).append(newHtml); $(this).removeClass('thread-infoRow'); }); }); // actions for somewhere =========== // remove unwanted HTML from deal description $('.thread--type-detail .userHtml').each(function () { // userhtml code from mydalz, need to find jafascript to save automatically :-( var myUserhtml = ['<div class="userHtml overflow--wrap-break space--t-3" data-handler="lightbox-xhr" data-lightbox-xhr="{"name":"threads"}">', '</div>', // sourround deal description ]; // get inner html var myHtml = $(this).html(); // remove unwanted Stuff: combined <div><br><br> stuff, created by cut'npaste html // not elegant, but works ... var newHtml = myHtml.replace(/<div>|<div><br>|<\/br>|<\/div>/gi,''); newHtml = myHtml.replace(/<p>|<p><br>/gi,'<br><br>'); newHtml = newHtml.replace(/<br><br><br>|<br><br><br><br>|<br><br><br><br><br>/gi,'<br><br>'); // replace original with modifyed html $(this).replaceWith(myUserhtml[0] + newHtml + myUserhtml[1]); }); } // END enabled } // show popup user info while click on avatar ... ====================== function EnstylerAvatarPopup(){ if (enUserLogin && GM_config.get('enConfUser')) { // remove second image from cardview addStyleString('.thread-footer-cell a img.avatar.vAlign--all-m.space--mr-1.thread-avatar {display: none;}'); EnstylerAvatarPopupDo(); } } // code used for MyDealz avatar popup, thanks to mydealz :-) var enPopupUser = ['<button data-handler="track popover" data-track="{"action":"show_short_user_profile","label":"engagement"}" data-popover="{"endpoint":"', '/short","target":"#template-popoverLoader","layout":[{"preset":"e","y":"50%","left":{"offset":0},"width":300,"maxWidth":"100%"}]}">', '</button>', ]; function EnstylerAvatarPopupDo() { // login needed ... (Error in Popup without login ...) // replace every avatar link without popup if (enUserLogin && GM_config.get('enConfUser')) { $('.thread-footer-cell a.user.linkPlain, .user.linkPlain.thread-user').each(function () { // get inner html and link to user profile var myHtml = $(this).html(); var mysrc = $(this).attr('href'); // seperate user name from image and add class user var myAvatar1 = myHtml.replace(/<span.*/,''); var myAvatar2 = myHtml.replace(/.*<span class=".* space--mr-1">/,'<span class=" space--mr-1 user link-plain">'); // show small / medium sized Avatar myAvatar1 = myAvatar1.replace('avatar--type-s','avatar--type-m'); //in Dealz if (GM_config.get('enConfAvatar')) { myAvatar1 = myAvatar1.replace('thread-avatar','avatar--type-m'); } // compose popup var myPopup = enPopupUser[0] + mysrc + enPopupUser[1] + myAvatar1 + enPopupUser[2] + '<a href="' + mysrc + '">'+ myAvatar2 + '</a>'; $(this).replaceWith(myPopup); }); } } // create select page or scrollwheel for page navigation ============= var EnstylerPageEnum='enPageEnum'; var selectList = document.createElement("select"); selectList.id = EnstylerPageEnum; selectList.setAttribute('class', EnstylerPageEnum); selectList.onchange = EnstylerPageAction; var EnstylerPageEnumDown='enPageEnumDown'; var selectListDown = document.createElement("select"); selectListDown.id = EnstylerPageEnumDown; selectListDown.onchange = EnstylerPageAction; function EnstylerPagePickerCreate() { // revome existing picker EnstylerPagePickerRemove(); // if enabled if (GM_config.get('enConfPagePicker')) { // init values and clear select list var page=1; var min=1; var max=1; $(selectList).empty(); // get page and max from pagenav if ( $('.text--color-charcoalTint').length ) { // remove linebreaks var pageHtml = $('.text--color-charcoalTint').html().replace(/\r?\n|\r/g); //locate actual page and last page page = pageHtml.replace( /.*>Seite /i ,''); page = page.replace( /<.*/i , ''); max = pageHtml.replace( /.*page=/ ,''); max = max.replace( /[^0-9].*/i , ''); if (page == '') {page=1;} if (max == '') {max=page;} } // create page select element var x; var last; var option; for (x = min; x <= max; ) { option = document.createElement("option"); option.text = x; selectList.add(option); //selectListDown.add(option); last = x; // non linear increment var diff = Math.abs(x-page); if ( x < 10 || diff < 5) { x++; } else if ( x < 1000 && diff > 600) { x += Math.floor(diff/100); } else { x += Math.floor(diff/2); } } // add last page if (page > max) { max=page;} if (last < max ) { option = document.createElement("option"); option.text = max; selectList.add(option); //selectListDown.add(option); } // set default value selectList.value = page; //selectListDown.value = page; // Deal Page if ($('.voteBar').length) { selectList.setAttribute('class', EnstylerPageEnum +' subNavMenu-link subNavMenu-btn voteBar--sticky-off--hide'); $('.voteBar--sticky-off--hide:last').before(selectList); } else { // overwiew page if (GM_config.get('enConfBtn')) { // Place Picker in subnav selectList.setAttribute('class', EnstylerPageEnum+' box--all-i subNavMenu-link subNavMenu-btn'); $('.subNav-label:last').before(selectList); } else { //place picker in MainNav selectList.setAttribute('class', EnstylerPageEnum+' js-navDropDown-messages vAlign--all-m'); if ($('.test-loginButton').length) { $('.test-loginButton').before(selectList); } else { $('.js-navDropDown-messages').before(selectList); } } } } } function EnstylerPagePickerCreateDo() { // get page and max from pagenav if ( $('.js-sticky .text--color-charcoalTint').length ) { // remove linebreaks var pageHtml = $('.js-sticky .text--color-charcoalTint').html().replace(/\r?\n|\r/g); //locate actual page and last page var page = pageHtml.replace( /.*>Seite /i ,''); page = page.replace( /<.*/i , ''); if (page == '') {page=1;} // set default value selectList.value = page; //selectListDown.value = page; } } // goto selected Page function EnstylerPageAction() { var enPage = 'page=' + $(this).val(); // remove page= and everthing behind var enUrl = enLocParser.toString().replace( /page=.*|#.*/ ,''); // add new page parameter if ( enUrl.endsWith('?') || enUrl.endsWith('&')) { enUrl += enPage; } else { enUrl += '?'+enPage; } // add #thread-comments for deal if (enSection == '/deals/') { enUrl += '#thread-comments';} window.location = enUrl; } function EnstylerPagePickerRemove() { // Removes pagepicker from the document $('.'+ EnstylerPageEnum).remove(); } // blacklist do not show dealz containing blacklistet words ========================== // search in kategorie, dealtitle, and username var enClassHidden = 'enClassHidden'; var enClassBlackDone = 'enClassBlackDone'; var enBlacklisted=0; var unwantedRegex = [ /[\[\]\(\)\{\}\?\.\:\;\!\"\*\+\ ]/g, // in White/Backlist /[\[\]\(\)\{\}\?\.\:\;\!\"\*\+\,]/g // in Dealtext ]; var enBlack; var enWhite; var enBlackTemp; function EnstylerBlacklist() { // if logged in and user is not in whitelist if (enUserLogin && ! GM_config.get('enConfWhitelist').includes(enUserName)) { // add actual user to whitelist GM_config.set('enConfWhitelist', '@'+enUserName +',' + GM_config.get('enConfWhitelist')); GM_config.setValue('enConfWhitelist', GM_config.get('enConfWhitelist')); } // convert Black/Whitelist to RegEx var myTemp=GM_config.get('enConfBlacklist'); myTemp = myTemp.replace(unwantedRegex[0], ''); myTemp = myTemp.replace(/^,|,$/g,''); enBlack = myTemp.replace(/(.),(.)/g,'$1|$2'); myTemp=GM_config.get('enConfWhitelist'); myTemp = myTemp.replace(/^,|,$/g,''); enWhite = myTemp.replace(/(.),(.)/g,'$1|$2'); enBlackTemp= GM_config.get('enConfHideColder'); EnstylerBlacklistDo(); } function EnstylerBlacklistDo() { if (!GM_config.get('enConfBlackEnable')) { return;} // process every article $('article').each(function () { if ($(this).hasClass(enClassBlackDone)) { return;} var myThread = '#'+$(this).attr('id'); // return if already done or return no deal if (!myThread.startsWith('#'+enDealMarker)) { return;} // mark as already seen $(this).addClass(enClassBlackDone); // get title, categorie, user var myDealText = $(myThread + ' .thread-category').text(); myDealText += ' ' +$(myThread + ' .thread-title a').text(); myDealText += ' @' +$(myThread + ' .user').text(); myDealText = myDealText.replace(unwantedRegex[1] ,' '); // Whitelist first // whitelist Regex, exit if found if (enWhite !='' && myDealText.match(new RegExp(enWhite,'i'))) { return; } //get temp var myVoteTemp = $(myThread + ' .vote-temp').text(); // blacklist vote temp if (parseInt(myVoteTemp) <= enBlackTemp) { $(this).addClass(enClassHidden); enBlacklisted++; EnstylerLastSeenSkip(myThread) return; } // blacklist last // blacklist Regex, rxit if found if (enBlack !='' && myDealText.match(new RegExp(enBlack,'i'))) { $(this).addClass(enClassHidden); enBlacklisted++; EnstylerLastSeenSkip(myThread) return; } }); // END Article // set label for unBlacklist button EnstylerBlacklistShow() } // blacklist support functions .... var enUnblackText = 'unBlacklist <NUM-BLACK> Dealz'; function EnstylerBlacklistShow() { enJSfieldDefs.enConfUnblacklist.label=enUnblackText.replace('<NUM-BLACK>',enBlacklisted) } function EnstylerBlacklistRemove() { enBlacklisted=0; EnstylerBlacklistShow() $('.'+enClassHidden).removeClass(enClassHidden); $('.'+enClassBlackDone).removeClass(enClassBlackDone); } function EnstylerBlacklistUnhide() { enBlacklisted=0; EnstylerBlacklistShow() $('.'+enClassHidden).removeClass(enClassHidden); } // Main Nav will stay on TOP of the screen ========================= function EnstylerFixedNav() { var myFixedCssMain='.nav { display: block; position: fixed; width: 100%; z-index: 120;} .subNav, .userProfile, .tabbedInterface {margin-top: 4.4em;}'; var myFixedCssSub ='.subNav {margin-top: 0 !important;} .nav-subheadline {margin-top: 4.4em;}'; if (GM_config.get('enConfNavFixed')) { // everywhere but in Deal detail, I like it like it is ... if (enSection != '/deals/' && enSection != '/gutscheine/' ){ // delete header element with active stuff, but keep inside HTML var mySavedHtml = $('header').html(); $('header').replaceWith(mySavedHtml); // CSS for everywhere addStyleString(myFixedCssMain); if (! enSection.match(/^\/$|^\/hot|^\/new|^\/settings|^\/discussed/)) { // additional CSS for categories addStyleString(myFixedCssSub); } } } } // the return of "gestern xx:xx Uhr" ============== var enNow; var DealDate; var TodayStart; var ShowTime; var EnstylerTimeSeen='enTimeSeen'; function EnstylerDealTime() { enNow = new Date(); enNow.setTime(EnstylerStartTime) DealDate=new Date(); TodayStart = new Date(enNow.getFullYear(), enNow.getMonth(), enNow.getDate()); ShowTime= GM_config.get('enConfDealMinTime')*3600*1000; EnstylerDealTimeDo(); } function EnstylerDealTimeDo() { if (GM_config.get('enConfDealTime')) { enNow.setTime(Date.now()) // process every article $('time').each(function () { // get Deal time Diff, return if no diff or already seen var myTime= $(this).text(); // next article if ( $(this).hasClass(EnstylerTimeSeen) || !myTime.startsWith('vor ')) { return;} // get Deal Time difference var h = myTime.replace(/.* ([0-9].*) h.*/, '$1'); if (h==myTime) h=0; else h=parseInt(h); var m = myTime.replace(/.* ([0-9].*) m.*/, '$1'); if (m==myTime) m=0; else m=parseInt(m); var s = myTime.replace(/.* ([0-9].*) s.*/, '$1'); if (s==myTime) s=0; else s=parseInt(s); // compose real deal time var myDealDiff = ((h*60+m)*60+s)*1000; // Offset deal DealDate.setTime( enNow.getTime() - myDealDiff ); // last midnigth if (DealDate < TodayStart) { $(this).text('gestern '+ DealDate.toString().slice(16, 21) +' Uhr'); // more than 6 hours ago } else if (myDealDiff > ShowTime){ $(this).text(myTime + ' (heute '+ DealDate.toString().slice(16, 21) +' Uhr)'); } else { return; } $(this).addClass(EnstylerTimeSeen); }); } } // mark last seen Deal in Highligth, Hot and New ============================ var enSec='off'; var enSeenArticle=''; // GM variables used here // store newest loaded deal // 'enNewestDealnew' // 'enNewestDealhot' // 'enNewestDeal' var enNewestBase='enNewestDeal' function EnstylerLastSeen(){ // only in main categories if(enSection.match(/^\/$|new$|hot$/)) { // get section and save enSec= enNewestBase + enSection.replace(/\//, ''); GM_setValue(enNewestBase+'LastSec', enSec) // mark last seen article enSeenArticle=GM_getValue(enSec); EnstylerLastSeenDo(); // save actual last seen $('article').each(function () { // get ThreadID an return if not enDealMarker var myThread = $(this).attr('id'); if (!myThread.startsWith(enDealMarker)) {return;} // when in base of section ... if(enLocParser.search == '') { //store actual seen GM_setValue(enSec, myThread); //store last seen GM_setValue(enSec+'Last', enSeenArticle); } // exit loop return false; }); } else { // if we are not on base of ancategorie restore last value enSec=GM_getValue(enNewestBase+'LastSec'); GM_setValue(enSec, GM_getValue(enSec+'Last')); } } function EnstylerLastSeenDo(){ // only in main categories if(enSec != 'off') { // mark last seen article if ( typeof enSeenArticle != 'undefined') { //store last marked GM_setValue(enSec+'Last', enSeenArticle); $('#'+enSeenArticle).addClass('enClassMarkArticle'); $('#'+enSeenArticle).prev().addClass('comments-marker'); } else { // first time GM_setValue(enSec, enDealMarker+'1'); } } } // article is not availible i.e. blacklisted function EnstylerLastSeenSkip(DealID) { // if article last seen one, skip to next if (DealID == '#'+enSeenArticle) { // magic, get ID of next article alert('SKIP') enSeenArticle=$(DealID).next().attr('id'); if (DEBUG) console.error('Skip Deal: '+DealID.substr(1)+' -> '+enSeenArticle) EnstylerLastSeenDo(); } } // AMAZON mobile redirect ================================== // workaround to not intercept myDealz redirects with GM_xmlhttp // stolen from amazon redirect mobile: https://greasyfork.org/de/scripts/19700 function enAmazonMobileRedirect() { var enMyLocation=enLocParser.toString(); // do we run on amazon? if (enMyLocation.startsWith("https://www.amazon")) { // redirect enabled? if (GM_config.get('enConfAmazonRedirect')) { // do it if (enMyLocation.includes("/gp/aw/d/")) { window.location.assign(enMyLocation.replace("/gp/aw/d/", "/dp/")) } else { window.location.assign(enMyLocation.replace("/gp/aw/ol/", "/gp/offer-listing/")); } } // Amazon but no redirect enabled return false; } return true; } // create button for display Config ====================== var EnstylerButton = 'EnstylerButton'; //var input = document.createElement('a'); // input.setAttribute('href', 'showEnstylerConfig()'); // input.setAttribute('id', EnstylerButton); var input = document.createElement('input'); input.type = 'button'; input.setAttribute('id', EnstylerButton); input.onclick = showEnstylerConfig; function EnstylerButtonCreate() { // add Enstyler Button to ... var myElement; var myMain=false; input.value = 'Enstyler'; EnstylerButtonRemove(); // MainNav or Deal if (GM_config.get('enConfBtn') || enSection.match(/deals\/|gutscheine\//)) { myMain=true; } // only if space left if ($(window).width() < GM_config.get('enConfBtnMinWidth')) { myMain=false; } if (myMain) { // add button to MainNav var Elements = document.getElementsByClassName("nav-link"); myElement = Elements[3]; input.setAttribute('class', 'vAlign--all-m nav-link-text'); input.setAttribute('style', ''); } else { // add button to SubNav myElement = document.getElementById('tour-filter'); input.setAttribute('class', 'box--all-i subNavMenu-link'); input.setAttribute('style', 'font-size: 1.28571em; font-weight: 700; top: 3px; left: -0.7em'); } // only if myElement exist if (myElement !== null) { myElement.appendChild(input); //insertAfter(input, myElement); } } // needed for Enstyler Homepage function EnstylerHomeButton() { // add Enstyler Button to ... input.value = 'Options'; var myElement = document.getElementById('style-settings'); input.setAttribute('style', 'font-size: 1.28571em; padding: 0.8em;'); // only if myElement exist if (myElement !== null) { //myElement.appendChild(input); insertAfter(input, myElement); } } function EnstylerButtonRemove() { // Removes button from the document $('#'+ EnstylerButton).remove } // ============= GM_config functions ======================================= var enJSAutoUpdate=GM_info.scriptWillUpdate; var enUpdateJSurl = "https://greasyfork.org/de/scripts/24243"; // production version var enUpdateInterval=1 * (24*60); // 1 day between update checks // define EnstylerJS GM_config elements var enJSfieldDefs = { // Part one: load external content -------- 'enstyler': { 'section': ['additonal features for Enstyler', ''], 'label': 'Update CSS...', // Appears on the button 'type': 'button', // Makes this setting a button input 'click': function() { // Function to call when button is clicked //GM_config.setValue('enEnVersion', 'no'); //GM_config.save(); //GM_config.open(); window.open('https://userstyles.org/styles/128262#style-info'); } }, 'enstylerJS': { 'label': 'Update UserScript...', // Appears on the button 'type': 'button', // Makes this setting a button input 'click': function() { // Function to call when button is clicked //GM_config.setValue('enJSVersion', 'no'); //GM_config.save(); //GM_config.open(); window.open(enUpdateJSurl); } }, 'dontCookies': { 'label': 'Mozilla no cookies...', // Appears on the button 'type': 'button', // Makes this setting a button input 'click': function() { // Function to call when button is clicked window.open('https://addons.mozilla.org/de/addon/i-dont-care-about-cookies/'); } }, // part two: EnstylerJS internal configuration options ------ 'Section': { // display next section, dont kow why ... 'section': ['Configuration', ''], 'type': 'hidden', // Makes this setting a hidden input }, // postion of enstyler "button" 'enConfBtn': { 'label': 'Enstyler in MainNav', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': false // Default value if user doesn't change it }, 'enConfBtnMinWidth': { 'label': 'if width is bigger than ', // Appears next to field 'type': 'int', // Makes this setting a text input 'min': 600, // Optional lower range limit 'max': 1200, // Optional upper range limit 'size': 4, // Limit length of input (default is 25) 'default': 850 // Default value if user doesn't change it }, 'enConfNavFixed': { 'label': 'Display FIXED MainNav', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': false // Default value if user doesn't change it }, // ehanced USerInfo 'enConfUser': { 'label': 'Show Popuop Userinfo', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // Default value if user doesn't change it }, 'enConfAvatar': { 'label': 'bigger Avatar for Popuop', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // Default value if user doesn't change it }, // enable filtering of external links 'enConfAmazonRedirect': { 'label': 'Amazon mobile redirect', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // Default value if user doesn't change it }, // */ // more Deal actions 'enConfMoreDeal': { 'label': 'additional Deal actions', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // Default value if user doesn't change it }, // more Deal actions // show real Dealtime 'enConfDealTime': { 'label': 'show real Deal Time', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // Default value if user doesn't change it }, 'enConfDealMinTime': { 'label': 'if older than Hours', // Appears next to field 'type': 'int', // Makes this setting a text input 'min': 1, // Optional lower range limit 'max': 24, // Optional upper range limit 'size': 4, // Limit length of input (default is 25) 'default': 6 // Default value if user doesn't change it }, // Page picker 'enConfPagePicker': { 'label': 'Enable Page Picker', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': false // Default value if user doesn't change it }, /* DISBALED check for Updates 'enConfCheckEnUpdate': { 'label': 'Check for Updates', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // Default value if user doesn't change it }, /**/ // Black/Whitelist input 'enConfBlackEnable': { 'label': 'Enable Black- / Whitelist', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // Default value if user doesn't change it }, 'enConfHideColder': { 'label': 'Blacklist if colder then', // Appears next to field 'type': 'int', // Makes this setting a text input 'min': -9999, // Optional lower range limit 'max': -9, // Optional upper range limit 'size': 4, // Limit length of input (default is 25) 'default': -999 // Default value if user doesn't change it }, 'enConfBlacklist': { 'label': 'Blacklist - deals, categories, @users', // Appears next to field 'type': 'text', // Makes this setting a text input 'size': 70, // Limit length of input (default is 25) 'default': 'Nutella, Bangood, @Admin' // Default value if user doesn't change it }, 'enConfWhitelist': { 'label': 'Whitelist', // Appears next to field 'type': 'text', // Makes this setting a text input 'size': 70, // Limit length of input (default is 25) 'default': '' // Default value if user doesn't change it }, 'enConfUnblacklist': { 'label': 'UnBlacklist', // Appears on the button 'type': 'button', // Makes this setting a button input 'click': function() { // Function to call when button is clicked EnstylerBlacklistUnhide(); } }, // display copy message at end of section ... 'copy': { '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>'], 'type': 'hidden', // Makes this setting a hidden input }, }; // define EnstylerJS GM_config elements var enHomefieldDefs = { // Part one: load external content -------- 'saveOpt': { 'section': ['save your CSS options for next visit', ''], 'label': 'Select your CSS on main page then come back and klick "Save" ', // Appears near textarea 'type': 'textarea', // Makes this setting a button input 'size': 70, //'click': function() { // Function to call when button is clicked // showUrl('https://userstyles.org/styles/128262#style-info'); } }, // display copy message at end of section ... 'copy': { '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>'], 'type': 'hidden', // Makes this setting a hidden input 'value': 'Some hidden value' // Value stored }, }; // display GM_copnfig as div, so we can apply CSS easy!! var enGMOptChange = false; var enGMFrame = document.createElement('div'); enGMFrame.setAttribute('class','GM_config'); document.body.appendChild(enGMFrame); // basic config panel formatting, everything else is formatted by enstyler var enCSS = ['.GM_config {left: 5% !iportant; top: 9% !important; height: auto !important; max-width: 35em !important;}', '.GM_config input, .GM_config button, .GM_config textarea { border: 1px solid; margin: 0.5em 0em 0.2em 1em; padding: 0.1em;}', '.GM_config .reset { font-size: 9pt; padding-right: 1em; }', '#GM_config_enstyler_var:after {content: ". <- please install CSS!"; font-weight: bold;}', '.enClassHidden, #EnPopup_closeBtn {display: none;}', ].join(" "); addStyleString(enCSS); var En_Popup = new GM_configStruct( { 'id': 'EnPopup', // You need to use a different id for each instance 'title': 'EnstylerJS - Info', 'fields': // Fields object { 'Text': // This is the id of the field { 'label': '', // Appears next to field 'type': 'textarea', // Makes this setting a text field 'default': '' // Default value if user doesn't change it } }, 'events': { 'open': function (doc) { // rename the buttons var config = this; doc.getElementById(config.id + '_saveBtn').textContent = ' OK '; //doc.getElementById(config.id + '_closeBtn').textContent = 'Cancel'; doc.getElementById(config.id + '_resetLink').textContent = ''; }, 'save': function() { enUpdateChecked=false; enCheckUpdates(); En_Popup.close(); }, 'close': function() { enGMConfigOpen=false;}, }, 'frame': enGMFrame // Element used for the panel } ); function showPopup(text) { En_Popup.fields['Text'].value = text; En_Popup.fields['Text'].reload(); En_Popup.open(); } var enGMConfigOpen=false; // EnstylerJS Config Panel anzeigen function showEnstylerConfig() { if(!enGMConfigOpen) { enGetHome(); GM_config.open(); enGMConfigOpen=true; } else { GM_config.close(); } } // EnstylerJS START ======================== if (!window.location.hostname.endsWith('userstyles.org')) { var enFixedNav=false; GM_config.init( { id: 'GM_config', title: !DEBUG ? 'EnstylerJS - Settings' : ' EnstylerJS - >> Debug <<', fields: enJSfieldDefs, 'events': // Callback functions object { //'init': function() { alert('onInit()'); }, // remove elements ich switch is checked or not 'open': function() { var enRemoveConfig = [ // { check: true, switch: 'enConfFilterLink', remove: 'externalMobileRedirect'}, { check: false, switch: 'enConfBtn', remove: 'enConfBtnMinWidth'}, { check: false, switch: 'enConfUser', remove: 'enConfAvatar'}, { check: false, switch: 'enConfDealTime', remove: 'enConfDealMinTime'}, { check: false, switch: 'enConfBlackEnable', remove: 'enConfWhitelist'}, { check: false, switch: 'enConfBlackEnable', remove: 'enConfBlacklist'}, { check: false, switch: 'enConfBlackEnable', remove: 'enConfHideColder'}, { check: false, switch: 'enConfBlackEnable', remove: 'enConfUnblacklist'} ]; enFixedNav=GM_config.get('enConfNavFixed'); // remove unneeded controls $(enRemoveConfig).each(function() { if (GM_config.get(this.switch) == this.check) { GM_config.fields[this.remove].remove(); } }); // remove / display update dialog if (enJSAutoUpdate) {GM_config.fields['enstylerJS'].remove();} }, //'reset': function() { alert('reset') }, // relaod page on close after save 'save': function() { if (!GM_config.get('enConfNavFixed') && GM_config.get('enConfNavFixed')!=enFixedNav) {window.location.reload(false);} EnstylerButtonCreate(); EnstylerPagePickerCreate(); EnstylerBlacklistRemove(); EnstylerBlacklist(); EnstylerFixedNav(); EnstylerDealTime(); GM_config.close(); GM_config.open(); }, 'close': function() { enGMConfigOpen=false;}, }, 'frame': enGMFrame // Element used for the panel } ); // dummy, do not delete function enGetHome() {;} // HACK: we are NOT on Amazon if (enAmazonMobileRedirect()) { // =============== START EnstyerJS =================== EnstylerInit(); EnstylerFixedNav(); EnstylerDealTime(); EnstylerLastSeen(); EnstylerBlacklist(); EnstylerAvatarPopup(); EnstylerDealActions(); // delay Pagepicker and repaeting actions after finishing everything else function EnstylerDelayedInit() { // don't know why, but works only if called with delay ... EnstylerButtonCreate(); EnstylerPagePickerCreate(); // track DOM change Events, debounce: wait 1000ms after mutiple events // then re-apply (somse) changes to dynamic loaded content, $('.fGrid-last2, .thread-list--type-card').bind("DOMSubtreeModified",$.debounce( 300, function(){ EnstylerLastSeenDo(); EnstylerDealTimeDo(); EnstylerBlacklistDo(); EnstylerAvatarPopupDo(); EnstylerDealActionsDo(); EnstylerPagePickerCreateDo(); })); } // wait until page is loaded completely if (document.readyState == 'loading' || document.readyState == 'interactive'){ // Greasemonkey and Tampermonky -> runs script on DOM ready -> wait for load if(DEBUG) console.error('Run on DOM ready'); $(window).bind("load", function() { EnstylerDelayedInit(); }); } else { // if script run on page loaded -> give some time to finish rendering if(DEBUG) console.error('Run on Document loaded'); sleepAsync(Date.now()-EnstylerStartTime).then(() => { EnstylerDelayedInit(); }); } } // NOT on Amazon // ============= EnStyler UserScript Homepage functions ======= // experimental support for EnStyler2 export / import } else { // we are on ujserstyle function enGetHome() { var myOptions=''; $('#style-settings select').each(function() { var myID = $(this).attr('id'); var myValue = $('#'+myID).val(); var myText = $('option[value='+ myValue +']').text(); myOptions +='#' + myID + ':' + myValue +':' + myText +';\n'; }); $('#style-settings input:checked').each(function() { var myID = $(this).attr('id'); var myValue = $('#'+myID).val(); var myText = $('label[for='+ myID +']').text(); myOptions +='#' + myID + ':' + myValue +':' + myText +';\n'; }); GM_config.set('saveOpt', myOptions); } function enSetHome() { // get saved options,remove newlines and split to settings array var myOptions=GM_config.get('saveOpt'); myOptions=myOptions.replace(/\n/g,''); var mySettings = myOptions.split(';'); // abort if no options found if (myOptions=='' || !myOptions.startsWith('#')) {return;} for (var i=0; i< mySettings.length; i++) { // each Setting has 3 fields seperated by :, but only 2 used var myField=mySettings[i].split(':'); if (myField[0].match(/^#setting/i)) { // select $(myField[0]).val(''); $(myField[0]).val(myField[1]); } else if (myField[0].startsWith('#option')) { // option $(myField[0]).prop('checked', true); } else { if (myField[0] != '') {alert('unkown option: "' + myField +'"');} } } } // activate config for Enstyler Homepage GM_config.init( { id: 'GM_config', title: 'Enstyler2 - Settings', fields: enHomefieldDefs, 'events': // Callback functions object { //'init': function() { alert('onInit()'); }, // remove elements ich switch is checked or not //'open': function() { enGetHome(); }, //'reset': function() { enGMOptChange = true; }, // relaod page on close after save 'save': function() { enSetHome(); GM_config.close();}, 'close': function() { enGMConfigOpen=false; }, }, 'frame': enGMFrame // Element used for the panel } ); // START Enstyler 2 Homepage EnstylerHomeButton(); // set saved options enSetHome(); } //=========== Support functions for actual use ====== // add CSS in to document function addStyleString(str) { var node = document.createElement('style'); node.innerHTML = str; document.body.appendChild(node); } // insertAfter like .insertBefore but as support function function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } // from https://gist.github.com/TheDistantSea/8021359 // returns 0 on equal, 1 on v1 newer, -1 on v2 newer function versionCompare(v1, v2) { var lexicographical = false, zeroExtend = true, v1parts = v1.split('.'), v2parts = v2.split('.'); function isValidPart(x) { return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x); } if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {return NaN; } if (zeroExtend) { while (v1parts.length < v2parts.length) v1parts.push("0"); while (v2parts.length < v1parts.length) v2parts.push("0"); } if (!lexicographical) { v1parts = v1parts.map(Number); v2parts = v2parts.map(Number); } for (var i = 0; i < v1parts.length; ++i) { if (v2parts.length == i) { return 1; } if (v1parts[i] == v2parts[i]) { continue; } else if (v1parts[i] > v2parts[i]) { return 1; } else { return -1; } } if (v1parts.length != v2parts.length) { return -1; } return 0; } // sleep time expects milliseconds, then execute code // NOTE: code runs in parallel (asnyc)! // Usage! // sleepAsync(500).then(() => { // Do something after the sleep! // }); function sleepAsync (time) { return new Promise((resolve) => setTimeout(resolve, time)); }