EnstylerJS

MyDealz Enstyler Frontend and enhanced features

اعتبارا من 04-11-2016. شاهد أحدث إصدار.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

ستحتاج إلى تثبيت إضافة مثل Stylus لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتتمكن من تثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

ستحتاج إلى تثبيت إضافة لإدارة أنماط المستخدم لتثبيت هذا النمط.

(لدي بالفعل مثبت أنماط للمستخدم، دعني أقم بتثبيته!)

// ==UserScript==
// @name        EnstylerJS
// @namespace   Enstyler
// @description MyDealz Enstyler Frontend and enhanced features
// @include     http://www.mydealz.de/*
// @include     https://www.mydealz.de/*
// @version     2.11.050
// @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==

// ========== RUN EnstylerJS =====================================
// create object for enstyler "Menu Button"

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.value = 'Enstyler';
    input.setAttribute('id', EnstylerButton)
    input.onclick = showEnstylerConfig;

function EnstylerInit () {
    // hide Enstyler2 CSS (c) text because we have a button now
    addStyleString('.threadWidget-footer::after {display: none !important};');
    EnstylerButtonCreate();
    
    // basic config panel formatting, everything else is formatted by enstyler
    var enCSS = ['#GM_config {left: 5% !important; top: 9% !important; height: auto !important; max-width: 35em !important;}',
             '#GM_config input, #GM_config button { border: 1px solid; margin: 0.5em 0em 0.2em 1em; padding: 0.1em;}',
             '#GM_config .reset { font-size: 9pt; padding-right: 1em; }',
            ].join(" ");
    addStyleString(enCSS);
}

// blacklist do not show dealz containing blacklistet words
// search in kategorie, dealtitle, and username
function EnstylerBlacklist() {
   ;
}



function EnstylerStart () {
    // ============ stuff to modify page content =============================

    // REGEX to detect external URL
    var REGEX_THREAD     = /^https?:\/\/www\.mydealz\.de\/visit\/thread(image)?\/\d+$/;
    var REGEX_DESC       = /^https?:\/\/www\.mydealz\.de\/visit\/threaddesc\/\d+\/\d+$/;
    var REGEX_COMMENT    = /^https?:\/\/www\.mydealz\.de\/visit\/comment\/\d+\/\d+$/;
    var REGEX_AMAZONMOB  = /^https?:\/\/www\.amazon\..*\/gp\/aw\/.*$/;
    //var REGEX_AMAZON     = /^https?:\/\/www\.amazon\..*$/;

    //* GM_xmlhhtpREquest not supported by firefox mobile :-((( 
    // abfangen aller links mit jQuery
    $('a').bind('click', function(){
         var url = this.href;

         // externer Link mit Redirect ...
         // Match REDIRECT URLs and open new Window with finalUrl
         if (GM_config.get('enConfFilterLink') && url.match(REGEX_THREAD) || url.match(REGEX_DESC) || url.match(REGEX_COMMENT)) {
             // Workaround: pre open window because of popup blockers
             var asyncWindow = window.open(url, '_blank');
         
             // now lookup redirecd external URL ...
             // alert("external URL detected");
             GM_xmlhttpRequest({
                 method: 'GET',
                 url: url,
                 // here we get the final URL from redirect
                 onload: function (response) {
                   // process final URL
                   var newUrl = response.finalUrl;
                   //alert(newUrl);
                   // lets see ...
                   if (newUrl.match(REGEX_AMAZONMOB)) {
                       newUrl = newUrl.replace("/gp/aw/d/", "/dp/");
                       newUrl = newUrl.replace("/gp/aw/ol/", "/gp/offer-listing/");
                       //alert("Amazon rewritten URL: " + newUrl);
                   }
                   // load processed URL in preopened window
                   asyncWindow.location = newUrl;
                 }    
             });
             // return without link processing by Browser
             return false;
         }
  
         // return with link processing in Browser
         return true;  
    }); //  - END GM_xmlhttpRequest */
} // END EnstylerStart



// add actions to tread overview @ some places ==================================
function EnstylerDealActions() {
  // 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 class="link ico ico--pos-l ico--type-comment-blue space--mr-3"', // comment 0+1
                       '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>',
                       '<a class="link text--color-blue ico ico--type-bookmark-blue ico--pos-l space--mr-3"', //un-bookmark 2+3
                       '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>',
                       '<a class="link text--color-blue ico ico--type-pencil-blue ico--pos-l space--mr-3"', // edit 4+5
                       '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>',
                       '<a 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="{&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>',
                     ];
  var PATTERN = [ /<ENSTYLER-HREF-HERE>/g,    // pattern to replace by deal link ...
                  /<ENSTYLER-THREADID-HERE>/g, // pattern to replace ID
                ]
    
  if (GM_config.get('enConfMoreDeal')) {
    var parser = location; // parse location 
    var pathname = parser.pathname;
    var username = pathname.replace(/.*profile\//,'');
    username = username.replace(/\/.*/,'');
    
    // no username ??
    if (username == "") {
        username = "unknown"; 
    } else {
       pathname = pathname.replace(username + '/',''); // remove username if path is longer
    }  
    //alert("username:" + username + " pfadname:" +pathname)
        
    // default for all Dealz: comment
    var myAction = enDealAction[0]+ enDealAction[1];

    // Action for special locations only ====================
    // saved Dealz panel 
    if (pathname.endsWith('profile/saved-deals') ){
        // add for user saved-dealz: un-bookmark
        myAction += enDealAction[2]+ enDealAction[3];
    }
    if (pathname.endsWith('profile/diskussion') || pathname.endsWith(username)){
        // add user dealz and discussions: comment edit
        myAction +=  enDealAction[4]+ enDealAction[5];
    }

    // we have an Action to add to an Deal!
    if (myAction != "") {
        //GM_log('Action:' + myAction);
        // every thread on page ...
        $('article').each(function () {
            // get ThreadID, Link to Deal and DealID
            var myThread = $(this).attr('id');
            var myDealHref = $('#' + myThread + ' .thread-title a').attr('href');
            var myDealID = myThread.replace('thread_','')
            
            // compose final HTML
            var newHtml= myOuterHtml[0] + myAction + myOuterHtml[1];
            newHtml = newHtml.replace(PATTERN[0], myDealHref);
            newHtml = newHtml.replace(PATTERN[1], myDealID);
            
            // append HTML to Deal
            $('#' + myThread +' .thread-infoRow').append(newHtml);
        });     
    } 
      
      
    // actions for everywhere  ==============
    // remove unwanted HTML from deal description
    $('.thread--type-detail .userHtml').each(function () {
        // userhtml code from mydalz, need to find jafascript to save automatically :-(
        var enUserhtml = ['<div class="userHtml overflow--wrap-break space--t-3" data-handler="lightbox-xhr" data-lightbox-xhr="{&quot;name&quot;:&quot;threads&quot;}">',
                          '</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 =  newHtml.replace(/<br><br><br>|<br><br><br><br>|<br><br><br><br><br>/gi,'<br><br>');      
        
        // replace original with modifyed html
        $(this).replaceWith(enUserhtml[0] + newHtml + enUserhtml[1]);        
    });

  } // END enabled    
}


// show popup user info while click on avatar ... ==============
function EnstylerAvatarPopup() {
    // code used for MyDealz avatar popup, thanks to mydealz :-)
    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;',
                   '/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;}]}">',
                   '</button>',
                   ];
    // remove second image from cardview
    if (GM_config.get('enConfUser')) { addStyleString('.thread-footer-cell a img.avatar.vAlign--all-m.space--mr-1.thread-avatar {display: none;}'); }

    // replace every avatar link without popup
    if (GM_config.get('enConfUser')) {
        $('.thread-footer-cell a.user.linkPlain, .user.linkPlain.thread-user').each(function () {
            var Iam = $(this);
            // get inner html and link to user profile
            var myHtml = Iam.html();
            var mysrc = Iam.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] + Iam.attr('href') + enPopupUser[1] + myAvatar1 +  enPopupUser[2] + '<a href="' + Iam.attr('href') + '">'+ myAvatar2 + '</a>';
            Iam.replaceWith(myPopup);
        });
    }
}

function EnstylerButtonCreate() {
    // add Enstyler Button to ...
    var myElement;
    if (GM_config.get('enConfBtn') && $(window).width() > GM_config.get('enConfBtnMinWidth')) { 
       // add button to MainNav
       var Elements = document.getElementsByClassName("nav-link");
       myElement = Elements[3]; 
       input.setAttribute('class', 'nvAlign--all-m nav-link-text');
    } 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);
    }
}

function EnstylerButtonRemove() {
        // Removes an element from the document
        var element = document.getElementById(EnstylerButton);
        element.parentNode.removeChild(element);
}

// ============= GM_config functions =======================================

// define GM_config elements
var fieldDefs = {
    // Part one: load external content --------
    'enstyler': { 
      'section': ['additonal features for Enstyler', ''],
      'label': 'Install / Update CSS...', // Appears on the button
      'type': 'button', // Makes this setting a button input
      'click': function() { // Function to call when button is clicked
               showUrl('https://userstyles.org/styles/128262#style-info'); }
    },

   '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
               showUrl('https://addons.mozilla.org/de/addon/i-dont-care-about-cookies/'); }
    },

    //* thhis has to be the last one,display only if internal version is disabled 
    'externalMobileRedirect': {
      'label': 'Amazon mobile redirect...', // Appears on the button
      'type': 'button', // Makes this setting a button input
      'click': function() { // Function to call when button is clicked
               showUrl('https://greasyfork.org/de/scripts/19700'); }
    }, // */

   // part two: EnstylerJS internal configuration options ------ 
   'hidden1': { // display next section, dont kow why ...
      'section': ['Configuration', ''],
        'type': 'hidden', // Makes this setting a hidden input
        'value': 'Some hidden value' // Value stored
   },

   // postion of enstyler "button"
   'enConfBtn': {
      'label': 'Show 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': 'only 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
    },

   // 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
  'enConfFilterLink': { 
      '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
    },

  
   // 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 cam apply CSS!!
var enGMOptChange = false;
var enGMFrame = document.createElement('div');
document.body.appendChild(enGMFrame);

GM_config.init(
  {
    id: 'GM_config',
    title: 'EnstylerJS - Settings', 
    fields: fieldDefs, 
   'events': // Callback functions object
     {
      //'init': function() { alert('onInit()'); },
      // do not diplay external mobile redirect is internal is activated
      'open': function() { 
          if (GM_config.get('enConfFilterLink')) {
              GM_config.fields['externalMobileRedirect'].remove();
              }
          if (!GM_config.get('enConfBtn')) {
              GM_config.fields['enConfBtnMinWidth'].remove();
              }
          if (!GM_config.get('enConfUser')) {
              GM_config.fields['enConfAvatar'].remove();
              }
        },
      //'reset': function() { enGMOptChange = true; },
      // relaod page on close after save
      'save':  function() { 
          //enGMOptChange = true;
          if (GM_config.get('enConfFilterLink')) {
              GM_config.fields['externalMobileRedirect'].remove();
            }
          EnstylerButtonRemove();
          EnstylerButtonCreate();
        },
      //'close': function() { if (enGMOptChange) { location.reload(); enGMOptChange = false;} },
     },
   'frame': enGMFrame // Element used for the panel
  }
);


// EnstylerJS Config Panel anzeigen
function showEnstylerConfig() {
    GM_config.open(); 
}

//=========== Support functions for actual use =======

// display website in external window
function showUrl(str) {
    var myDeco = "innerheight=800,innerwidth=600";
    var myName = "enstyler";
    
    // workaround for not working window.focus(): close an existing window first
    var myWindowShow = window.open('', myName, "width=100,height=100").close();
    myWindowShow = window.open(str, myName, myDeco);
}

// add CSS in to document
function addStyleString(str) {
    var node = document.createElement('style');
    node.innerHTML = str;
    document.body.appendChild(node);
}
// 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));
}

// like .insertBefore but as function
function insertAfter(newNode, referenceNode) {
    referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

// ============== START EnstyerJS =============
EnstylerInit();
EnstylerStart();
EnstylerBlacklist();
EnstylerAvatarPopup();
EnstylerDealActions();

// track DOM change Events, debounce: wait 500ms after mutiple events
// then re-apply (somse) changes to dynamic loaded content, 
$('.fGrid-last2, .thread-list--type-card').bind("DOMSubtreeModified",$.debounce( 500, function(){
   //GM_log('DOMSubtreeModified detected!!!');
    EnstylerBlacklist();
    EnstylerAvatarPopup();

}));