Year of the Dragon: Through May 28th, claim free Expansion Pack (excluding Vecna Unleashed) or a Greater Elixir of Discovery! Speak to Xatheral in the Hall of Heroes. edit

Game mechanicsNewbie guideIn developmentDDO StoreSocial Media


ChallengesClassesCollectablesCraftingEnhancementsEpic DestiniesFavorFeats

GlossaryItemsMapsMonstersPlacesQuestsRacesReincarnationSkillsSpells


Please create an account or log in to build a reputation and unlock more editing privileges, and then visit DDO wiki's IRC Chat/Discord if you need any help!

MediaWiki:Gadget-vectorMenu.js

From DDO wiki
Jump to navigation Jump to search

Note: After saving, you may have to bypass your browser's cache to see the changes, you can click here or try one of the methods below..

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl+F5 or Ctrl+r ( Command+r on a Mac)
  • Google Chrome: Press Ctrl+ Shift+R ( Command+ Shift+R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl+F5
  • Konqueror: Click Reload or press F5
  • Opera: Clear the cache in Tools ‣ Preferences
/**********************************************************************
 **                ***WARNING: GLOBAL GADGET FILE***                 **
 **         any changes to this file will affect many users          **
 **          please discuss changes on the talk page                 **
 **     (consider dropping the script author a note as well...)      **
 **********************************************************************
 **        SOURCED BY [[MediaWiki:Gadget-vectorMenu.js]]             **
 **********************************************************************/

//<nowiki>
// Version       : 1.0
// Author        : [[U:Technical 13]]
// Script        : [[MW:Gadget-vectorMenu.js]]
// Description   : [[MWt:Gadget-vectorMenu]]
// Documentation : [[MW:Gadget-vectorMenu]]
// GitHub        : 
// Prerequisites : MediaWiki version 1.8 or higher
//                 jStorage via ResourceLoader
//                 Any modern browser or IE8+
// Based on      : https://github.com/MusikAnimal/MoreMenu v4.3.2
//                ( http://enwp.org/User:MusikAnimal/MoreMenu docs )
//
// Text available under the Creative Commons Attribution-ShareAlike License (CC BY-SA 3.0)
//

( function( mw, $ ) {
  var api = new mw.Api(),
    namespaceNumber = mw.config.get( 'wgNamespaceNumber' ),
    canonicalSpecialPageName = mw.config.get( 'wgCanonicalSpecialPageName' ),
    isPageProtected = ( !!mw.config.get( 'wgRestrictionEdit' ) &&
      mw.config.get( 'wgRestrictionEdit' ).length ) ||
      ( !!mw.config.get( 'wgRestrictionCreate' ) &&
      mw.config.get( 'wgRestrictionCreate' ).length ),
    serverName = mw.config.get( 'wgServer' ),
    siteName = mw.config.get( 'wgSiteName' ),
    userGroups = mw.config.get( 'wgUserGroups' ),
    contentLanguage = mw.config.get( 'wgContentLanguage' ),
    articleId = mw.config.get( 'wgArticleId' ),
    mwDBname = mw.config.get( 'wgDBname' ),
    pageName = mw.config.get( 'wgPageName' ),
    actionType = mw.config.get( 'wgAction' ),
    userName = mw.config.get( 'wgRelevantUserName' ) || '',
    isUserSpace,
    metaUserGroups,
    userPermissions,
    currentDate = new Date();
  var escapedPageName = pageName.replace( /[!'"()*]/g, escape ),
    encodedPageName = encodeURIComponent( pageName ),
    escapedUserName = userName.replace( /[?!'()*]/g, escape ),
    encodedUserName = encodeURIComponent( userName );

  $( '#ca-protect,#ca-unprotect,#ca-delete,#ca-undelete' ).remove();// Admin stuff
  $( '#ca-move' ).remove();// Everyone has a move link
  if ( mw.user.options.get( 'gadget-wikEd' ) !== '1' ) {// wikEd bug workaround...
    $( '#ca-purge,#p-cactions' ).remove();//Remove purge and empty menu if not using wiEd.
  }

  var userMenuList = {
    'User' : {
      'User logs' : {
        'All logs' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName } )
        },
        'Block log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName, type: 'block' } ),
          permissions : [ 'block' ]
        },
        'Deletion log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName, type: 'delete' } ),
          permissions : [ 'delete' ]
        },
        'Move log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName, type: 'move' } ),
          permissions : [ 'move' ]
        },
        'Protection log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName, type: 'protect' } ),
          permissions : [ 'protect' ]
        },
        'Review log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName, type: 'review' } ),
          permissions : [ 'review' ]
        },
        'Upload log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName, type: 'upload' } ),
          permissions : [ 'upload' ]
        },
        'User creation log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName, type: 'newusers' } ),
          groups : [ 'user' ] // any user can create new accounts at [[Special:CreateAccount]]
        },
        'User rights log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', user: userName, type: 'rights' } ),
          addRemoveGroups : true
        }
      },/*
      'RfXs' : {
        'RfAs' : {
          url : mw.util.getUrl( 'Special:PrefixIndex/Wikipedia:Requests_for_adminship/' + userName ),
          style : 'display:none',
          title : 'Requests for Adminship'
        },
        'RfBs' : {
          url : mw.util.getUrl( 'Special:PrefixIndex/Wikipedia:Requests_for_bureaucratship/' + userName ),
          style : 'display:none',
          title : 'Requests for Bureaucratship'
        },
      },*/
      'Blocks' : {
        'Block user' : {
          url : mw.util.getUrl( 'Special:Block/' + userName ),
          userPermissions : 'block',
          blocked : false
        },
        'Change block' : {
          url : mw.util.getUrl( 'Special:Block/' + userName ),
          userPermissions : 'block',
          blocked : true
        },
        'Unblock user' : {
          url : mw.util.getUrl( 'Special:Unblock/' + userName ),
          blocked : true,
          userPermissions : 'block'
        },
        'View block' : {
          url : mw.util.getUrl( 'Special:BlockList', { wpTarget: userName } ),
          blocked : true,
          style : 'color: #EE1111'
        },
        'View block log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', page: userName, type: 'block' } )
        }
      },
      'IP lookup' : {
        'WHOIS' : {
          url : 'http://whois.domaintools.com/' + escapedUserName,
          ipOnly : true
        },
        'rDNS' : {
          url : 'https://www.robtex.com/ip/' + escapedUserName + '.html',
          ipOnly : true
        },
        'Traceroute' : {
          url : 'http://www.domaintools.com/research/traceroute/?query=' + escapedUserName,
          ipOnly : true
        },
        'Geolocate' : {
          url : 'http://whatismyipaddress.com/ip/' + escapedUserName,
          ipOnly : true
        }
      },
      'Change rights' : {
        url : mw.util.getUrl( 'Special:UserRights', { user: 'User:' + userName } ),
        groups : [ 'user' ],
        userAddRemoveGroups : true
      },
      'Checkuser' : {
        url : mw.util.getUrl( 'Special:CheckUser/' + userName ),
        userPermissions : [ 'checkuser' ]
      },
      'Contributions' : {
        url : mw.util.getUrl( 'Special:Contributions/' + userName )
      },
      'Deleted contributions' : {
        url : mw.util.getUrl( 'Special:DeletedContributions/' + userName ),
        userPermissions : [ 'deletedhistory', 'deletedtext' ]
      },
      'Suppressed contribs' : {
        url : mw.util.getUrl( 'Special:Log/suppress', { offender: userName } ),
        userPermissions : [ 'oversight' ]
      },
      'Email user' : {
        url : mw.util.getUrl( 'Special:EmailUser/' + userName ),
        groups : [ 'user' ]
      },
      'Uploads' : {
        url : mw.util.getUrl( 'Special:ListFiles', { user: userName, ilshowall: '1' } ),
        groups : [ 'user' ]
      },
      'User groups' : {
        url : mw.util.getUrl( 'Special:ListUsers', { limit: 1, username: userName } ),
        groups : [ 'user' ]
      },
      'User rights changes' : {
        url : mw.util.getUrl( 'Special:Log', { user: '' , page: 'User:' + userName, type: 'rights' } ),
        groups : [ 'user' ]
      },
    }
  };

  var pageMenuList = {
    'Page' : {
      'Page logs' : {
        'All logs' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', page: pageName } )
        },
        'Deletion log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', page: pageName, type: 'delete' } )
        },
        'Move log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', page: pageName, type: 'move' } )
        },
        'Protection log' : {
          url : mw.util.getUrl( 'Special:Log', { action: 'view', page: pageName, type: 'protect' } )
        }
      },/*
      'XfDs' : {
        url : 'javascrit:void(0)'
      },*/
      'Protect page' : {
        url : serverName + '/index.php?title=' + encodedPageName + '&action=protect',
        userPermissions : [ 'protect', 'stablesettings' ]
      },
      'Change protection' : {
        url : mw.util.getUrl( pageName, { action: 'protect' } ),
        userPermissions : [ 'protect', 'stablesettings' ],
        isProtected : true
      },
      'Delete page' : {
        url : serverName + '/index.php?title=' + encodedPageName + '&action=delete' + ( $( '#delete-reason' ).text() ? '&wpReason=' + $( '#delete-reason' ).text() : ''),
        userPermissions : [ 'delete' ],
        pageExists : true
      },
      'Undelete page' : {
        url : mw.util.getUrl( 'Special:Undelete/' + pageName ),
        userPermissions : [ 'undelete' ],
        pageDeleted : true
      },
      'Edit intro' : {
        url : serverName + '/index.php?title=' + encodedPageName + '&action=edit&section=0',
        namespaceRestrict : [ 0, 1, 2, 3, 4, 5, 500, 501 ],
        pageExists : true
      },
      'Latest diff' : {
        url : mw.util.getUrl( pageName, { action: 'view', diff: mw.config.get( 'wgCurRevisionId' ) } ),
        pageExists : true
      },
      'Move page' : {
        url : mw.util.getUrl( 'Special:MovePage/' + pageName ),
        userPermissions : [ 'move' ],
        pageExists : true
      },
      'Purge cache' : {
        url : mw.util.getUrl( pageName, { action: 'purge', forcelinkupdate: true } ),
        pageExists : true
      },
      'Compare page' : {
        url : mw.util.getUrl( 'Special:ComparePages', { page1: pageName, page2: ( pageName.substr( 0, pageName.indexOf( '/' ) ) || pageName ) } ),
        pageExists : true
      }/*,
      'Subpages' : {
        url : mw.util.getUrl( 'Special:PrefixIndex/' + pageName + '/' ),
      },*/// Not yet available, but I want it to be.
    }
  };

  var dependencies = [ ];

  if ( !$.jStorage ) dependencies.push( 'jquery.jStorage' );
  if ( !Object.keys ) dependencies.push( 'es5-shim' );

  // initialize script
  mw.loader.using( dependencies, function() {
    var menus = [ ];

    if ( namespaceNumber === 2 || namespaceNumber === 3 || canonicalSpecialPageName === 'Contributions' || !!mw.util.getParamValue( 'user' ) ) {
      isUserSpace = true;
      menus.push( userMenuList );
    }
    if ( namespaceNumber >= 0 ) menus.push( pageMenuList );

    init( menus, function(data) {
      completePageLinks();
      if ( isUserSpace ) completeUserLinks( data[ 0 ].query );
    } );
  } );

  // custom callback functions for these menus

  function completePageLinks() {
    $( '#c2-page-xfds' ).hide();

    $( '#p-views ul' ).on( 'beforeTabCollapse', function() {
      if ( $( '#ca-history' ).hasClass( 'collapsible' ) ) {
        $( '#p-page2' ).find( 'ul' ).append( $( '#ca-history' ).detach() );
      }
    } );
  }

  function completeUserLinks( query ) {
    apiGet( {
      list : 'logevents',
      letype : 'block',
      letitle : 'User:' + userName,
      lelimit : 1
    } ).done( function( data ) {
      if ( data.query.logevents.length === 0) {
        $( '#c2-user-blocks-view_block_log' ).remove();
      }
      if ( $( '#c2-user-blocks' ).find( 'li' ).length === 0 ) {
        $( '#c2-user-blocks' ).remove();
      }
    } );

    /*var rfxs = {
      'DDO:Requests for adminship' : 'rfas',
      'DDO:Requests for bureaucratship' : 'rfbs',
    };

    $( '#c2-user-rfxs' ).hide();*/
  }

  function addListeners() {
    $( '.c2-hover-menu' ).each( function() {
      $( this ).hover( function() {
        $el = $( this ).find( '.submenu' );
        $el.css( {
          left : $( this ).outerWidth(),
          top : '-1px',
          'border-top-width' : 1
        } );
        $el.show();
      }, function() {
        $( this ).find( '.submenu' ).hide();
      } );
    } );
  }

  function apiGet( params ) {
    return api.get(
      $.extend( params, {
        action: 'query'
      } )
    );
  }

  function canAddRemoveGroups( groups, permissions ) {
    if ( permissions && permissions.indexOf( 'userrights' ) >= 0 ) return true;
    var ret = false;
    for ( var i = 0; i < groups.length; i++ ) {
      if ( metaUserGroups[ groups[ i ] ] && metaUserGroups[ groups[ i ] ].addRemoveGroups ) {
        ret = true;
        break;
      } else {
        // clear cache and fallback to false
        $.jStorage.deleteKey( 'metaUserGroups' );
        ret = false;
      }
    }
    return ret;
  }

  // scope is an array, returns true if all elements in 'array' exist in scope
  function containsArray( array, index, last ) {
    if ( !index ) {
      index = 0;
      last = 0;
      this.sort();
      array.sort();
    }
    return index === array.length
      || ( last = this.indexOf( array[ index ], last ) ) > -1
      && containsArray.call( this, array, ++index, ++last );
  }

  function generateMenuContent( tabName, menuList, userData, userPermissions ) {
    var html = '';
    $.each( menuList, function( name, action ) {
      if ( action ) {
        var newHtml = '';
        if ( !action.url ) {
          newHtml += '<li style="position: relative;" id="' + linkId( tabName, name ) + '" class="c2-hover-menu">' +
                '<a style="font-weight: bold">' + name + '&hellip;</a>' +
                  '<div class="submenu menu" style="display: none; position: absolute;"><ul>';

          $.each( action, function( k, v ) {
            newHtml += linkHtml( tabName, k, v, name, userData, userPermissions );
          } );
          newHtml += '</ul></div></li>';
          if ( $( newHtml ).last().find( '.submenu li' ).length === 0 ) {
            newHtml = '';
          }
        } else {
          newHtml += linkHtml( tabName, name, action, null, userData, userPermissions );
        }
        html += newHtml;
      }
    } );
    return html;
  }

  function hasConditional( permitted, given ) {
    permitted = $.makeArray( permitted );
    given = $.makeArray( given );
    if ( !permitted.length ) {
      return true;
    } else if ( !given.length ) {
      return false;
    } else {
      var valid = false;
      for ( var i = 0; i < given.length; i++ ) {
        if ( $.inArray( given[ i ], permitted ) >= 0 ) {
          valid = true;
          break;
        }
      }
      return valid;
    }
  }

  function linkId( tabName, name, parent ) {
    return 'c2-' + sanitize( tabName.toLowerCase() ) + '-' + ( parent ? sanitize( parent ) + '-' : '') + sanitize( name );
  }

  function linkHtml( tabName, name, action, parent, userData, userPermissions ) {
    var validations =
      /* namespace          */ ( hasConditional( action.namespaceRestrict, namespaceNumber ) || !hasConditional( action.namespaceExclude, namespaceNumber ) ) &&
      /* existence          */ ( ( action.pageExists && articleId > 0 ) || ( !action.pageExists ) ) &&
      /* deleted            */ ( action.pageDeleted ? articleId === 0 && mw.config.get( 'wgIsArticle' ) === false : true ) &&
      /* protected          */ ( action.isProtected ? isPageProtected : true ) &&
      /* database           */ hasConditional( action.databaseRestrict, mwDBname ) &&
      /* notice project     *//* hasConditional( action.noticeProjectRestrict, noticeProject ) &&*/
      /* user's user groups */ hasConditional( action.userGroups, userGroups ) &&
      /* user's permissions */ hasConditional( action.userPermissions, userPermissions ) &&
      /* can change groups  */ ( action.userAddRemoveGroups ? canAddRemoveGroups( userGroups, userPermissions ) : true );

    if ( isUserSpace ) {
      // FIXME: find something better than userData.invalid === '' for checking if IP
      validations &=
        /* their user groups  */ hasConditional( action.groups, userData.groups ) &&
        /* their permissions  */ hasConditional( action.permissions, userData.rights ) &&
        /* they're blocked    */ ( action.blocked !== undefined ? !!userData.blockid === action.blocked : true ) &&
        /* can change groups  */ ( action.addRemoveGroups ? canAddRemoveGroups( userData.groups, userData.rights ) : true ) &&
        /* IP                 */ ( action.ipOnly ? userData.invalid === '' : true );
    }

    if ( !!validations ) {
      return '<li id=' + linkId( tabName, name, parent ) + '><a href="' + action.url + '" title="' + ( action.title || '' ) + '" ' + ( action.style ? 'style="' + action.style + '"' : '' ) + '>' + name + '</a></li>';
    } else {
      return '';
    }
  }

  function sanitize( name ) {
    return name.toLowerCase().replace( / /g, '_' );
  }

  function init( menus, fn ) {
    var promises = new Array( 3 ),
        cacheDate = $.jStorage.get( 'mmCacheDate' ),
        expired = cacheDate < currentDate;

    if ( isUserSpace ) {
      promises[ 0 ] = apiGet( {
        list : 'users|blocks',
        ususers : userName,
        bkusers : userName,
        usprop : 'blockinfo|groups|rights',
        bkprop : 'id'
      } );
    }

    if ( expired || !( userPermissions = $.jStorage.get( 'mmUserRights' ) ) ) {
      promises[ 1 ] = mw.user.getRights();
    }

    if ( expired || !( metaUserGroups = $.jStorage.get( 'mmMetaUserGroups' ) ) ) {
      promises[ 2 ] = apiGet( {
        meta : 'siteinfo',
        siprop : 'usergroups'
      } );
    }

    $.when.apply( this, promises ).done( function ( data, userRightsData, metaData ) {
      var userData;

      if ( data ) {
        userData = data[ 0 ].query.users[ 0 ];

        if ( !userData ) {
          // FIXME: add functionality to only show menu based on custom function;
          //    temporary fix so that script doesn't break on pages of users that don't exist
          isUserSpace = false;
          for ( var j = 0; j < menus.length; j++ ) {
            if ( !!menus[ j ].User ) menus.splice( j, 1 );
          }
        } else if ( userData.invalid === '' ) {
          userData.groups = [ ];
          userData.rights = [ ];
          if ( data[ 0 ].query.blocks.length ) {
            userData.blockid = data[ 0 ].query.blocks[ 0 ].id;
          }
        }
      }

      if ( userRightsData ) {
        userPermissions = $.jStorage.set( 'mmUserRights', userRightsData );
      }

      if ( metaData ) {
        metaUserGroups = {};
        $.each( metaData[ 0 ].query.usergroups, function ( i, el ) {
          metaUserGroups[ el.name ] = {
            permissions : el.rights,
            addRemoveGroups : !!el.add || !!el.remove
          };
        } );
        $.jStorage.set( 'mmMetaUserGroups', metaUserGroups );
      }

      if ( expired ) {
        var newDate = new Date();
        $.jStorage.set( 'mmCacheDate', newDate.setDate( newDate.getDate() + 7 ) );
      }

      for ( var i = 0; i < menus.length; i++ ) {
        var tabName = Object.keys( menus[ i ] )[ 0 ];
        var html =  '<div id="p-' + tabName.toLowerCase() + '2" class="vectorMenu" style="z-index: 99;">' +
          '<h3><span>' + tabName + '</span><a href="#" title="' + tabName + '"></a></h3>' +
          '<div class="menu"><ul>';
        html += generateMenuContent( tabName, menus[ i ][ tabName ], userData, userPermissions );
        html += '</ul></div></div>';
        if ( $( '#p-cactions' )[ 0 ] ) {
          $( html ).insertAfter( $( '#p-cactions' ) );
        } else {
          $( html ).insertAfter( $( '#p-views' ) );
        }
        addListeners();
      }

      if ( typeof fn === 'function' ) fn( data, userPermissions );
    } );
  }
} )( mediaWiki, jQuery );
//</nowiki> [[C:Gadgets]]