您需要先安装一个扩展,例如 篡改猴、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 https://www.preisjaeger.at/* // @include https://www.mydealz.de/* // @include https://userstyles.org/styles/128262/* // @include https://www.amazon.*/gp/aw/* // @version 2.12.222 // @grant GM_getValue // @grant GM_setValue // @require http://code.jquery.com/jquery-3.1.1.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 = ''; const EnstylerStartTime=Date.now(); // Parse location for later use const enLocParser=location; var DEBUG=false; // Basic Initialisation ========================== 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'); } else { //restore old last seen if user logs in // use this variant for dynamic loaded content click ... $(document).on("click",'.test-loginButton', EnstylerLastSeenLast); } // get Section (first element in path) enSection= enLocParser.pathname.replace(/\/([^\/]+\/*).*/,'/$1'); } // add actions @ some places ================================== // additional Deal Actions ======================= // code used for MyDealz Dealz actions, thanks to mydealz :-) const 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"}">', '<span class="hide--toW3">Sag was dazu</span><span class="hide--fromW3 hide--toW2">Sag</span>', '', '</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"}">', '<span class="hide--toW3">Von Liste entfernen</span><span class="hide--fromW3 hide--toW2">Enft</span>', '', '</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}">', '<span class="hide--toW3">Bearbeiten</span><span class="hide--fromW3 hide--toW2">Bearb</span>', '', '<span></a>', '<a title="Als Mail versenden" class="link text--color-blue ico ico--type-code-blue ico--pos-l space--mr-3"'+ // mail 12+13+15 'href="mailto:?subject=<ENSTYLER-TEXT-HERE>" <span class="hide--toW3">', '<span class="hide--toW3">Mail versenden</span><span class="hide--fromW3 hide--toW2">Mail</span>', '', '<span></a>', ]; const enDealMarker='#thread_'; const enDealNoAction='.ico--type-clock-grey, .vote-temp--colder'; var enDealAdd='', enDealUnbook=false; var enDealActionMailFooter=''; function EnstylerDealActions(){ // if logged in and enabled ... if (enUserLogin && GM_config.get('enConfMoreDeal')) { // compose Footer enDealActionMailFooter = ('%0D%0A%0D%0A-- %0D%0A'+ enInternationalName + ':%0D%0A'+ $('footer ul li:first p').html().replace(/.*<br>/g,'')); // 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: first comment enDealAdd = enDealAction[0]+ enDealAction[1+myText] + enDealAction[3]; // Action for special locations only =========== switch(true) { case (pathname.endsWith('profile/saved-deals')): // add for user saved-dealz: un-bookmark enDealAdd += enDealAction[4]+ enDealAction[5+myText]; + enDealAction[7]; enDealUnbook=true; break; case (pathname.endsWith('profile/diskussion')): case (pathname.endsWith(enUserName)): // add user dealz and discussions: comment edit enDealAdd += enDealAction[8]+ enDealAction[9+myText] + enDealAction[11]; break; } // default last: add mail to enDealAdd += enDealAction[12]+ enDealAction[13+myText] + enDealAction[15]; // Compose final Deal Actions enDealAdd= enDealActionOuterHtml[0] + enDealAdd + enDealActionOuterHtml[1]; // do it ... EnstylerDealActionsDo(); } } // surrounding myDealz HTML const enDealActionOuterHtml = [ '<span class="js-options bg--em bRad--a space--h-3 space--v-3 space--mt-3 text--b">', '</span>']; function EnstylerDealActionsDo() { // if logged in and enabled ... if (enUserLogin && GM_config.get('enConfMoreDeal')) { // every thread on thread page ... $('article:not(.'+enClassHidden+')').each(function () { // get infoRow var myInfoRow=$('.thread-infoRow', $(this)); if (!myInfoRow.length || $(enDealNoAction, $(this)).length) {return;} // get Titel, Link, DealID num var myDeal =$('.thread-title a', $(this)); var myDealHref = myDeal.attr('href'); // compose mail subject var mySub=encodeURIComponent(enInternationalName+': '+myDeal.text()); //if (mySub.length < 100 && $('.thread-price', $(this)).length) { // mySub += encodeURIComponent(' ->_' +$('.thread-price', $(this)).text().replace(/\t/g,'')); //} // compose final HTML var newHtml = enDealAdd.replace(enPATTERN[0], myDealHref) .replace(enPATTERN[2], truncStringWord(mySub, 160, '%20') +'&body=' +mySub +'%0D%0A%0D%0A' +myDealHref +enDealActionMailFooter); if (enDealUnbook) {newHtml = newHtml.replace(enPATTERN[1], ('#'+$(this).attr('id')).replace(enDealMarker,''));} // append HTML to Deal myInfoRow.append(newHtml); myInfoRow.removeClass('thread-infoRow'); }); // actions for somewhere =========== // remove unwanted HTML from deal description $('.thread--type-detail .userHtml').each(function () { // 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(/<\/p>|<\/div>/gi,'').replace(/<div>|<p>/gi,'<br><br>').replace(/<br>(<br>)*<br>/gi,'<br><br>'); $(this).html(newHtml); }); } // 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 :-) const 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>', ]; const enClassAvatarDone = 'enClassAvatarDone'; function EnstylerAvatarPopupDo() { // login needed ... (Error in Popup without login ...) // replace every avatar link without popup if (enUserLogin && GM_config.get('enConfUser')) { var myBigAvatar=GM_config.get('enConfAvatar'); // each avatar $('.thread-footer-cell a.user.linkPlain, .user.linkPlain.thread-user').each(function () { if( $(this).hasClass(enClassAvatarDone)|| $(this).hasClass(enClassBlackDone)) return; $(this).addClass(enClassAvatarDone); // 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 myAvatar = myHtml.replace(/<span.*/,'').replace(/avatar--type-s/,'avatar--type-m'); //var myAvatar2 = myHtml.replace(/.*<span class=".* space--mr-1">/,'<span class=" space--mr-1 user link-plain">'); if (myBigAvatar) { myAvatar = myAvatar.replace(/thread-avatar/,'avatar--type-m'); } // compose popup $(this).html(enPopupUser[0] + mysrc + enPopupUser[1] + myAvatar + enPopupUser[2] + '<a href="' + mysrc + '">'+ myHtml.replace(/.*<span class=".* space--mr-1">/,'<span class=" space--mr-1 user link-plain">') + '</a>'); }); } } // create select page or scrollwheel for page navigation ============= const EnstylerPageEnum='enPageEnum'; const selectList = document.createElement("select"); selectList.id = EnstylerPageEnum; selectList.setAttribute('class', EnstylerPageEnum); selectList.onchange = EnstylerPageAction; function EnstylerPagePickerCreate() { // revome existing picker EnstylerPagePickerRemove(); // if enabled if (GM_config.get('enConfPagePicker')) { // init values and clear select list var page=1, 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 if( isNaN(page = parseInt(pageHtml.replace( /.*>Seite /i ,'')) )) { page=1;} if( isNaN(max = parseInt(pageHtml.replace( /.*page=/ ,'')) )) { max=page;} } // create page select element for (var x = 1; x <= max; ) { var option = document.createElement("option"); option.text = x; selectList.add(option); var 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 ) { var option = document.createElement("option"); option.text = max; selectList.add(option); } // set default value selectList.value = page; // placement of MAIN Picker var MainPicker= ['.js-navDropDown-messages', //Element EnstylerPageEnum+' js-navDropDown-messages vAlign--all-m' //class ]; // login button present in Mainnav if ($('.test-loginButton').length) { MainPicker[0]='.test-loginButton'; //Element } // in deal always in sticky votebar (was in subnav) if ($('.voteBar').length) { MainPicker= [ '.voteBar--sticky-off--hide:last', // Element EnstylerPageEnum +' subNavMenu-link subNavMenu-btn voteBar--sticky-off--hide' //class ]; } // Main Picker add class and palce before element selectList.setAttribute('class',MainPicker[1]); $(MainPicker[0]).before(selectList); } } function EnstylerPagePickerDo() { // get page and max from pagenav if ( $('.js-sticky .text--color-charcoalTint').length ) { //locate actual page incl remove line breaks var page = parseInt($('.js-sticky .text--color-charcoalTint').html().replace(/\r?\n|\r/g).split( '--toW2">Seite ')[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 const enClassHidden = 'enClassHidden'; const enClassBlackDone = 'enClassBlackDone'; var enBlacklisted=0; const unwantedRegex = [ /[\[\]\(\)\{\}\?\.\:\;\!\"\*\+\ ]/g, // in White/Backlist /[\[\]\(\)\{\}\?\.\:\;\!\"\*\+\,]/g // in Dealtext ]; var enBlack, enBlackTrue; var enWhite, enWhiteTrue; 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 enBlack=RegExp(GM_config.get('enConfBlacklist').replace(unwantedRegex[0], '').replace(/^,|,$/g,'').replace(/(.),(.)/g,'$1|$2'),'i'); ''.match(enBlack) ? enBlackTrue=false : enBlackTrue=true ; enWhite=RegExp(GM_config.get('enConfWhitelist').replace(/^,|,$/g,'').replace(/(.),(.)/g,'$1|$2'),'i'); ''.match(enWhite) ? enWhiteTrue=false : enWhiteTrue=true ; enBlackTemp= GM_config.get('enConfHideColder'); EnstylerBlacklistRemove() EnstylerBlacklistDo(); } function EnstylerBlacklistDo() { if (!GM_config.get('enConfBlackEnable') || ( !enBlackTrue && enBlackTemp < -900)) { return;} // process every article $('article:not(.'+enClassBlackDone+', .threadWidget-item)').each( function () { // mark as already seen $(this).addClass(enClassBlackDone); // get title, categorie, user, remove unwanted chars var myDealText = ($('.thread-category',$(this)).text() +' ' +$('.thread-title a',$(this)).text() +' @' +$('.user',$(this)).text()).replace(unwantedRegex[1] ,' '); // whitelist Regex, exit if found if ( enWhiteTrue && myDealText.match(enWhite)) { return; } // vote temp & blacklist if (parseInt($('.vote-temp', $(this)).text()) <= enBlackTemp || enBlackTrue && myDealText.match(enBlack)) { $(this).addClass(enClassHidden); enBlacklisted++; EnstylerLastSeenSkip('#'+$(this).attr('id')); } }); // END Article // set label for unBlacklist button EnstylerBlacklistShow() } // blacklist support functions .... const enUnblackText = 'unBlacklist <ENSTYLER-TEXT-HERE> Dealz'; function EnstylerBlacklistShow() { enJSfieldDefs.enConfUnblacklist.label=enUnblackText.replace(enPATTERN[2],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 ========================= const myFixedCSS = [ /* 0 everywhere */'.enFixedNav { display: block; position: fixed; width: 100%; z-index: 120;} .subNav, .userProfile, .tabbedInterface, .splitPage-wrapper {margin-top: <ENSTYLER-TEXT-HERE>px;}', /* 1 subnav */ '.subNav {margin-top: 0 !important;} .nav-subheadline {margin-top: <ENSTYLER-TEXT-HERE>px;}', /* 2 diskussion */'.tGrid.page2-center.height--all-full {margin-top: calc(<ENSTYLER-TEXT-HERE>px + 10px);}' ]; function EnstylerFixedNav() { 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('<header class="enFixedNav">'+mySavedHtml+'</header>'); // fixed NAV for everywhere var myFixedStyle=myFixedCSS[0]; // additionla CSS for different sections if (enSection == '/diskussion/') { myFixedStyle+=myFixedCSS[2]; } if ($('.nav-subheadline').length || enSection=='/profile/') { // additional CSS for categories myFixedStyle+=myFixedCSS[1]; } myFixedStyle= myFixedStyle.replace(enPATTERN[2], enMainHeigth) addStyleString(myFixedStyle) } } } // 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, optimization: not if class TiemSeen $('time:not(.'+EnstylerTimeSeen+')').each(function () { // get Deal time, var myTime= $(this).text(); // next article if less than an h or older than 24h if ( myTime.length <9 || !myTime.startsWith('v')) {return;} // compose deal offset var myDealDiff = (parseInt(myTime.replace(/.* ([0-9].*) h.*/, '$1'))*60+parseInt(myTime.replace(/.* ([0-9].*) m.*/, '$1')))*60000; DealDate.setTime( enNow.getTime() - myDealDiff ); // last midnigth if (DealDate < TodayStart) { $(this).text('gestern '+ DealDate.toString().slice(16, 21) +' Uhr'); // more than x hours ago } else if (myDealDiff > ShowTime){ $(this).html(myTime + ' (<span class="hide--toW2">heute </span>'+ DealDate.toString().slice(16, 21) +' Uhr)'); } else { return; } $(this).addClass(EnstylerTimeSeen); }); } } // mark last seen Deal in Highligth, Hot and New ============================ var enSec=''; var enSeenArticle=''; // GM variables used here // store newest loaded deal // 'enNewestDeal...new' // 'enNewestDeal...hot' // 'enNewestDeal...' // international support added const enNewestBase='enNewest'+enLocParser.hostname.replace('www',''); var LastSeenOnce=true; function EnstylerLastSeen(){ // only once and in main categories if(LastSeenOnce) { LastSeenOnce=false; // store last seen for Main catergories if(enSection.match(enMainSectionMatch) && enLocParser.search == '') { // get section and save enSec= enNewestBase + enSection.replace(/\//, ''); GM_setValue(enNewestBase+'LastSec', enSec) // get last seen article enSeenArticle=GM_getValue(enSec); if ( typeof enSeenArticle == 'undefined') {enSeenArticle='';} EnstylerLastSeenDo(); // save actual last seen $('article:not(.threadWidget-item)').each(function () { // pinned ? if (!('.cept-pinned-flag',$(this)).length) {return;} //store actual seen GM_setValue(enSec, $(this).attr('id')); //store last seen GM_setValue(enSec+'Last', enSeenArticle); // exit loop return false; }); } else { // if we are not in main categorie => restore last value EnstylerLastSeenLast() } } } function EnstylerLastSeenDo(){ // only in main categories if(enSec != '') { // mark last seen article if (enSeenArticle != '') { //store last marked GM_setValue(enSec+'Last', enSeenArticle); $('#'+enSeenArticle).addClass('enClassMarkArticle'); } else { // first time GM_setValue(enSec, 'thread_1'); } } } // restore last seen from last last seen function EnstylerLastSeenLast(){ // restore last value enSec=GM_getValue(enNewestBase+'LastSec'); GM_setValue(enSec, GM_getValue(enSec+'Last')); } // 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 enSeenArticle=$(DealID).next().attr('id'); EnstylerLastSeenDo(); } } // compose Nav Menu items ======================================= // i.e. create button for display Config ====================== // define pattern actions here, incl. international support const enMainSectionMatch=/^\/$|^\/hot$|^\/new$|^\/settings$|^\/discussed$|^\/hei%C3%9F$|^\/diskutiert$/; const enPATTERN = [ /<ENSTYLER-HREF-HERE>/g, // 0 pattern to insert link ... /<ENSTYLER-THREADID-HERE>/g, // 1 pattern to insert ID /<ENSTYLER-TEXT-HERE>/g, // 2 pattern to insert Text ]; const enNavEntry='enNavEntry'; const enMenuItemCode = [ /*0 MainNav*/ '<a class="enNavEntry navMenu-link" id="<ENSTYLER-THREADID-HERE>" href="<ENSTYLER-HREF-HERE>" data-handler="track" data-track="{"action":"goto_main_target","beacon":true}"><span class="navMenu-link-ico ico ico--type-discussion-navMenuLayerItem navMenu-ico--selected--type-discussion navMenu-ico--hover--type-discussion"></span><ENSTYLER-TEXT-HERE></a>', /*1 SubNav */ '<li class="enNavEntry subNavMenu-item--separator test-tablink-discussed"><a href="<ENSTYLER-HREF-HERE>" class="subNavMenu-item subNavMenu-link space--h-4 vAlign--all-m" id="<ENSTYLER-THREADID-HERE>" data-handler="track" data-track="{"action":"goto_menu_target sort","label":"diskutiert","beacon":true}"><span class="box--all-i size--all-xl vAlign--all-m"><ENSTYLER-TEXT-HERE></span><span class="js-vue-container--threadcount" data-handler="vue" data-vue="{"count":null}"></span></a></li>', /*2 MainBut */ '<a class="enNavEntry navMenu-link" id="<ENSTYLER-THREADID-HERE>"><span class="navMenu-link-ico ico ico--type-discussion-navMenuLayerText"></span><ENSTYLER-TEXT-HERE></a>', /*3 SubBut */ '<li class="enNavEntry subNavMenu-item--separator test-tablink-discussed"><a class="subNavMenu-item subNavMenu-link space--h-4 vAlign--all-m" id="<ENSTYLER-THREADID-HERE>"><span class="box--all-i size--all-xl vAlign--all-m"><ENSTYLER-TEXT-HERE></span></a></li>' ]; const enMenuMain=0; const enMenuMainButton=2; //const const enMenuSub=1; const enMenuSubButton=3; const enMenuItemLength= enMenuItemCode.length; // Enstyler Button const EnstylerButton = 'EnstylerButton'; // compose default Enstyler Menu function EnstylerMenuActions(){ EnstylerNavRemove() if (!enInternational) { // MyDealz only: alle Diskussionen EnstylerAddNav(enMenuMain,'Alle Diskussionen', 'https://www.mydealz.de/diskussion','enMainDiscussion') } // add Enstyler Homepage EnstylerAddNav(enMenuMain, 'Enstyler Homepage', 'https://www.mydealz.de/diskussion/enstyler-856062" target="_blank','enMainHomepage', 'building'); // add EnstylerJS config EnstylerAddNav(enMenuMainButton, 'Enstyler Einstellungen', showEnstylerConfig, EnstylerButton, 'page'); // add to Sub Nav //EnstylerAddNav(enMenuSubButton, 'Enstyler' , showEnstylerConfig, EnstylerButton) } // add to Nav ====================== // nav = menu action // text = menu text // target = URL to show, in case of Button function to call // Icon can be home, tag, scissors, free, discussion (default), building, star, snowflake, page (button), star (button) var enNavIconPat='--type-discussion'; function EnstylerAddNav(nav,text,target,ID, Icon) { // exit if no defined Menu action if (nav >= enMenuItemLength) {return;} if (typeof Icon == 'undefined' || Icon == '') Icon=enNavIconPat; var isFunc=false; // compose menu entry var myEntry = enMenuItemCode[nav].replace(enPATTERN[1],ID).replace(enPATTERN[2],text); if(Icon !=enNavIconPat) { myEntry = myEntry.split(enNavIconPat).join('--type-'+Icon)} // target can be a function if (typeof target === "function") { isFunc=true; } else { myEntry = myEntry.replace(enPATTERN[0],target); } switch(nav) { case enMenuMain: // Main Nav add delayed case enMenuMainButton: // first Main menu entry, start listen to klick if(enAddMain == '') { $('.nav-link.navMenu-trigger').click(debounce( 300, EnstylerMainDo)); } enAddMain += myEntry; if (isFunc) { enAddMainFunc[enAddMainCount++]= { ID: ID , target: target}; } break; /* case enMenuSub: // Sub Nav, add now case enMenuSubButton: // ad to Subnav, click if visible $('.subNavMenu-list').append(myEntry); if(isFunc) { $('#'+ID).click(target); } // handler if dropdown, start listen to klick if(enAddSub == '') { $('.subNavMenu-trigger').click(debounce( 300, EnstylerSubDo)); enAddSub='done'; } if(isFunc) { enAddSubFunc[enAddSubCount++]= { ID: ID , target: target}; } break; /**/ } } // Show items in Sub / Main Menu ===== // store ID and function to call on click var enAddMain=''; var enAddMainFunc= [ ]; var enAddMainCount=0; function EnstylerMainDo() { // klick event handler, call with debounce( 300) to wait until menu is created and avoid double klicks //add items $(enAddMain).insertBefore('.popover-content nav .navMenu-div:first'); // create space for new entrys var myMenu=$('.popover--mainNav'); // +35px per new items var myHeigth= 35*(enAddMain.split(enNavEntry).length -1) + parseInt(myMenu.attr('style').split('height: ')[1]); myMenu.attr('style',myMenu.attr('style').replace(/height: [0-9.]*px/,'height: '+myHeigth+'px')); // add button callbacks for (var i=0; i<enAddMainCount; i++ ) { $('section #' + enAddMainFunc[i].ID).click(enAddMainFunc[i].target); } } /* var enAddSub=''; var enAddSubFunc= [ ]; var enAddSubCount=0; function EnstylerSubDo() { // klick event handler, call with debounce( 300) to wait until menu is created and avoid double klicks //add items if(DEBUG) console.error('Add Menu Items to Sub ...') for (var i=0; i<enAddSubCount; i++ ) { $('section #' + enAddSubFunc[i].ID).click(enAddSubFunc[i].target); } } /**/ function EnstylerNavRemove() { // Clear Menu Items stored enAddMain=''; enAddMainFunc= [ ]; enAddMainCount=0; $('.navMenu-page').unbind('click'); // remove visible items $('.'+enNavEntry).remove(); } // ============= GM_config functions ======================================= const enJSAutoUpdate=GM_info.scriptWillUpdate; var enUpdateWindow; const enInternationalSite=enLocParser.hostname.replace('www',''); const enInternationalName=capitalizeFirstLetter(enInternationalSite.replace(/^\.|\..*/g,'')); const enInternational=(enInternationalName != 'Mydealz'); // dom we run on FF? GM hast noch scriptHandler, USI may or may not, so NOT Tampermonkey is OK const isMozilla=(typeof GM_info.scriptHandler == "undefined" || !GM_info.scriptHandler.startsWith('Tamp')) // define EnstylerJS GM_config elements const 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 enUpdateWindow=window.open('https://userstyles.org/styles/128262#style-info', 'UserCSS', 'width=600,height=950,left=0,top=0'); } }, '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 enUpdateWindow=window.open(!DEBUG ? 'https://greasyfork.org/scripts/24243-enstylerjs/code/EnstylerJS.user.js' : ' https://greasyfork.org/scripts/24244-enstylerjs-develop/code/EnstylerJS Develop.user.js', 'UserScript', 'width=110,height=110,left=0,top=0'); // give 5s to start update, then close sleepAsync(5000).then(function() { enUpdateWindow.close(); }); } }, '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/firefox/addon/self-destructing-cookies/'); } }, // part two: EnstylerJS internal configuration options ------ 'Section': { // display next section, dont kow why ... 'section': ['Configuration', ''], 'type': 'hidden', // Makes this setting a hidden input }, 'enConfNavFixed': { 'label': 'Display FIXED MainNav', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // 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 // Page picker 'enConfPagePicker': { 'label': 'Enable Page Picker', // Appears next to field 'type': 'checkbox', // Makes this setting a checkbox input 'default': true // Default value if user doesn't change it }, // 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 }, // 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(); } }, // used to not destroy saved Enstyler2 Options 'saveOpt': { 'type': 'hidden', // Makes this setting a button input }, }; // define EnstylerJS GM_config elements const 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, }, // 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_config as div, so we can apply CSS easy!! ====================== const enGMFrame = document.createElement('div'); enGMFrame.setAttribute('class','GM_config'); document.body.appendChild(enGMFrame); // basic config panel formatting, everything else is formatted by enstyler const enCSS = ['.GM_config {left: 5% !iportant; top: 8% !important; height: auto !important; max-width: 35em !important; background-color: white;}', '.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; }', '.enClassHidden, #EnPopup_closeBtn {display: none;}', ].join(" "); // get colors of page to integrate better in international pages // and save hight of navigation ... var enMainHeigth; if ($('.nav').length){ // pepper site detected =============== // calc colors and topx var myBgColor=$('.nav').css('background-color'); var enGmCss = ' .GM_config {background-color: '+ shadeRGBColor(myBgColor, -0.30) + ' !important; color: '+ shadeRGBColor(myBgColor, 0.50); enMainHeigth = parseInt($('header').outerHeight()); enGmCss += '; top: '+ enMainHeigth +'px !important;}' // calc navlink hover color enGmCss += ' .nav-link-text:hover, .js-navDropDown-messages:hover, .js-navDropDown-activities:hover { background-color: ' +shadeRGBColor(myBgColor, 0.11)+ ' !important;}'; } // add predefined styles and page colors addStyleString(enCSS+enGmCss); // EnstylerJS Config Panel anzeigen ===================== var enGMConfigOpen=false; function showEnstylerConfig () { if(!enGMConfigOpen) { enGetHome(); GM_config.open(); // hide menu $('.popover--mainNav').remove(); enGMConfigOpen=true; } else { GM_config.close(); } } // 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; } // EnstylerJS START ============================================ var EnstylerStartupDelay; if (!window.location.hostname.endsWith('userstyles.org')) { var enFixedNavLast=false; GM_config.init( { // international sites support id: enInternational ? 'GM_config' + enInternationalSite : '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: 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'} ]; enFixedNavLast=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();} if (!isMozilla) {GM_config.fields['dontCookies'].remove();} }, //'reset': function() { alert('reset') }, // relaod page on close after save 'save': function() { // disabeling FixedNav can only done with reload if (!GM_config.get('enConfNavFixed') && GM_config.get('enConfNavFixed')!=enFixedNavLast) {window.location.reload(false);} // restart Enstyler magic GM_config.close(); EnstylerStart(); EnstylerMenuActions(); EnstylerPagePickerCreate(); // show changes in config after processing magic GM_config.open(); }, 'close': function() { enGMConfigOpen=false;}, }, 'frame': enGMFrame // Element used for the panel } ); // Enstyler internal Startup functions ====================== // HACK: we are NOT on Amazon if (enAmazonMobileRedirect()) { // dummy, do not delete function enGetHome() {;} // Start Enstyler Magic function EnstylerStart() { EnstylerFixedNav(); EnstylerDealTime(); EnstylerLastSeen(); EnstylerBlacklist(); EnstylerAvatarPopup(); EnstylerDealActions(); } // delayed actions after finishing everything else function EnstylerDelayedInit() { // don't know why, but works only if called with delay ... EnstylerMenuActions(); EnstylerPagePickerCreate(); // track DOM change Events, debounce: wait 1000ms after mutiple events // then re-apply (somse) changes to dynamic loaded content, // $('.cept-event-deals, .thread-list--type-card').bind("DOMSubtreeModified",$.debounce( 400, function(){ $('.js-pagi-bottom').bind("DOMSubtreeModified", debounce( 100, function(){ EnstylerLastSeenDo(); EnstylerPagePickerDo(); EnstylerDealTimeDo(); EnstylerBlacklistDo(); EnstylerAvatarPopupDo(); EnstylerDealActionsDo(); })); } // =============== MAIN: START EnstyerJS =================== EnstylerInit(); EnstylerStart(); EnstylerStartupDelay=Date.now()-EnstylerStartTime; // wait until page is loaded completely if (document.readyState == 'loading' || document.readyState == 'interactive'){ // Greasemonkey and Tampermonky -> runs script on DOM ready -> wait for load $(window).bind("load", function() { EnstylerDelayedInit(); }); } else { // if script run on page loaded -> give some time to finish rendering sleepAsync(EnstylerStartupDelay).then(function() { EnstylerDelayedInit(); }); } } // END Enstyler MAIN // ============= EnStyler UserScript Homepage functions ======= // support for EnStyler2 export / import } else { // we are on ujserstyle if (DEBUG) console.error('On Userstyle ...') var input = document.createElement('input'); input.type = 'button'; input.setAttribute('id', EnstylerButton); input.onclick = showEnstylerConfig; input.value = 'Save Options'; function EnstylerHomeButton() { $('#'+EnstylerButton).remove() input.setAttribute('style', 'font-size: 1.1em; padding: 0.8em;'); $('#style-settings').after(input); } function enGetHome() { var myOptions=''; $('#style-settings select').each(function() { var myID = $(this).attr('id'); var myValue = $(this).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 = $(this).val(); var myText = $('label[for='+ myID +']').text(); myOptions +='#' + myID + ':' + myValue +':' + myText +';\n'; }); GM_config.set('saveOpt', myOptions); } function enSetHome() { input.value = 'Save Options'; // get saved options,remove newlines and split to settings array var myOptions=GM_config.get('saveOpt'); // if(DEBUG) console.error('Saved Options: ' + myOptions); 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++) { //if(DEBUG) console.error('process:' + mySettings[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 +'"');} } } // update shown otions HideShowLogoSelect(); HideShowEnstyler(); } // close Window after Click on Update function closeOnClick () { sleepAsync(10000).then(function() { window.close(); }); } $(".install").click(closeOnClick); // show if options not saved function showNotSaved() { input.value = 'Options not saved!'; EnstylerHomeButton(); } $("#style-settings").click(showNotSaved); function ShowHideItem(selectID, hideVal, jqSelektor) { if ($(selectID).val() == hideVal) { $('#style-settings '+jqSelektor).parent().addClass(enClassHidden); } else { $('#style-settings '+jqSelektor).parent().removeClass(enClassHidden); } } // remove / display logo selection function HideShowLogoSelect() { ShowHideItem('#setting-455195', 'ik-logo1', 'label:contains(MyDealz Logo)' ); } $('#setting-455195').change(HideShowLogoSelect); // remove / display enstyler options function HideShowEnstyler() { ShowHideItem('#setting-451668', 'ik-compact1', 'label:contains(|---)' ); } $('#setting-451668').change(HideShowEnstyler); // activate config for Enstyler Homepage GM_config.init( { id: 'GM_config', title: 'Enstyler2 - Settings', fields: enHomefieldDefs, 'events': // Callback functions object { 'save': function() { enSetHome(); EnstylerHomeButton(); 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); } function capitalizeFirstLetter(string) { return string[0].toUpperCase() + string.slice(1); } // truncate String add word boundary function truncStringWord(string, n, worddelim ){ if (typeof worddelim === 'undefined') worddelim=' '; if (string.length > n) { string = string.substr(0,n-1); return string.substr(0,string.lastIndexOf(worddelim)) + '...'; } return string; }; // sleep time expects milliseconds, then execute code // NOTE: code runs in parallel (asnyc)! // Usage! // sleepAsync(500).then(function() { // Do something after the sleep! // }); function sleepAsync(time) { var p = new Promise(); setTimeout(function() { p.resolve(); }, time); return p.promise(); } // make colors ligther or darker // http://stackoverflow.com/questions/5560248 //color = "rbg(63,131,163)"; //lighterColor = shadeRGBColor(color, 0.5); // rgb(159,193,209) //darkerColor = shadeRGBColor(color, -0.25); // rgb(47,98,122) function shadeRGBColor(color, percent) { var f=color.split(","),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=parseInt(f[0].slice(4)),G=parseInt(f[1]),B=parseInt(f[2]); return "rgb("+(Math.round((t-R)*p)+R)+","+(Math.round((t-G)*p)+G)+","+(Math.round((t-B)*p)+B)+")"; } // https://remysharp.com/2010/07/21/throttling-function-calls // $('input.username').keypress(debounce(250, function)); // Ensytler debounce Funtionen, modified: parameter swapped, no args passed // todo: dynamic delay? function debounce(delay, fn) { var timer = null; return function () { clearTimeout(timer); timer = setTimeout(function () { fn.call(this); }, delay); }; }