User:C.Ezra.M/staffhl.js

From Bulbapedia, the community-driven Pokémon encyclopedia.
Jump to navigationJump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/**
 * A script to highlight staff members' usernames.
 * This only does the job of applying attributes, there are no enforced colors.
 * This is for a11y purposes, but most importantly, to crack down on use of `!important`.
 * 
 * @author Keyacom
 */

/** Settings for this script */
window.staffhlSettings = {
  /**
   * Should it use the Fetch API?
   * @ignore Not yet implemented!
   */
  fetch: false, // TODO
  /**
   * Name of the variable for staffhl.js cache. Set to `null` to disable caching.
   * @type string|null
   * @ignore Not yet implemented!
   */
  localStorageVar: 'staffhlCache', // TODO
  /**
   * The group hierarchy. Also, only the users in these usergroups will ever be
   * found with the query.
   * @type string[]
   */
  groupHierarchy: [
    "editboard",
    "bureaucrat",
    "sr-admin",
    "sysop",
    "jr-admin",
    "bot",
  ],
  /**
   * Groups to exclude from the resulting attribute value.
   * @type string[]
   */
  exclude: [
    "*",
    "user",
    "autoconfirmed",
    "emailconfirmed",
  ],
  /** The name of the attribute to store the user group information in.
   * Should be in form of a space-separated token list to allow querying
   * with CSS using the `[attr-name~="..."]` syntax.
   * @type string
   */
  attr: "data-sthl-ugroups",
  /** The prefix regex for user page links. This check happens after
   * URL-decoding the page title.
   */
  linkPrefix: /^User:/,
  /** Limit of users fetched in one request */
  reqLimit: 50,
  /** Attempt to skip the limit with recursion? */
  skipLimit: false,
  /** The condition for the highlighting to happen */
  condition() {
    return mw.config.get('wgNamespaceNumber') === -1 || mw.config.get('wgAction') === 'history'
  },
  /** The function passed into the map method of the jQuery object to parse links. This must return a user name.
   */
  linkMapper(element, index) {
    const linkPart = element.href.split('/').at(-1)
    if (element.href.split('/').at(-2) === 'w') {
      const params = new URLSearchParams(linkPart)
      const pageName = params.get('title') // URL decoding happens under the hood
      if (pageName !== null) {
        return pageName.split('/')[0].replace(this.linkPrefix, '')
      }
    } else {
      return linkPart.split('?')[0].split('/')[0].replace(this.linkPrefix, '')
    }
  }
  /*
  linkMapper(index, element) {
    const linkPart = element.href.split('/').at(-1)
    if (element.href.split('/').at(-2) === 'w') {
      const params = new URLSearchParams(linkPart)
      const pageName = params.get('title') // URL decoding happens under the hood
      if (pageName !== null) {
        return pageName.split('/')[0].replace(this.linkPrefix, '')
      }
    } else {
      return linkPart.split('?')[0].split('/')[0].replace(this.linkPrefix, '')
    }
  }
  */
}

/**
 * Converts a date into a compact timestamp. For now, supports precision down to
 * the hour.
 * @param date {Date} the `Date` object
 * @returns string
 */
function toTimestamp(date) {
  return [
    [date.getUTCFullYear(), 4],
    [date.getUTCMonth(), 2],
    [date.getUTCDate(), 2],
    [date.getUTCHours(), 2],
  ]
    .map(e => e[0].toString().padStart(e[1], '0'))
    .join('')
}

/**
 * Converts a compact timestamp to a Date object.
 * @param timestamp {string} the timestamp
 * @returns Date
 */
function fromTimestamp(timestamp) {
  const year = timestamp.slice(0, 4)
  const month = timestamp.slice(4, 6)
  const date = timestamp.slice(6, 8)
  const hours = timestamp.slice(8, 10)
  return new Date(year, month, date, hours)
}

function addAttrs(w = {}) {
  const settings = window.staffhlSettings
  const api = new mw.Api()
  // https://bulbapedia.bulbagarden.net/w/api.php?action=query&list=allusers&format=json&augroup=sysop|editboard|jr-admin|sr-admin|retired-staff|bureaucrat&auprop=groups
  api.get({
    action: 'query',
    list: 'allusers',
    format: 'json',
    augroup: window.staffhlSettings.groupHierarchy,
    auprop: 'groups',
    aulimit: window.staffhlSettings.reqLimit,
    ...w,
  }).done(data => {
    if (settings.skipLimit && data['continue']) {
      addAttrs({...w, aufrom: data['continue'].aufrom})
    }
    const links = $('.mw-body a.mw-userlink')
    links.get().map((e, i) => [e, settings.linkMapper(e, i)]).forEach(([e, n]) => {
      const users = data.query.allusers
      const userObj = users.find(u => u.name === n)
      if (userObj !== undefined) {
        const groups = userObj.groups.filter(gp => settings.groupHierarchy.includes(gp) && !settings.exclude.includes(gp))
        $(e).attr(settings.attr, groups.join(' '))
      }
    })
  })
}

if (window.staffhlSettings.condition()) {
  mw.hook('wikipage.content').add(addAttrs)
  addAttrs()
}