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 C.Ezra.M
 */

/** Settings for this script */
window.staffhlSettings = {
  /**
   * If `true`, `fetch()` is used. If `false`, `mw.Api` is used instead.
   */
  fetch: true,
  /**
   * 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 `maxage` parameter for caching.
   * @type number
   */
  maxage: 1800, // 30 minutes
  /**
   * The group hierarchy. Also, only the users in these usergroups will ever be
   * found with the query.
   * @type string[]
   */
  groupHierarchy: [
    "editboard",
    "bureaucrat",
    "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: true,
  /** 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 username with underscores replaced by spaces.
   */
  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, '').replace("_", " ")
    }
  },

  /**
   * Converts a date into a compact timestamp. For now, supports precision down to
   * the hour.
   * @param date {Date} the `Date` object
   * @returns string
   */
  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
   */
  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)
  },

  getData_fetch(w = {}) {
    const params = new URLSearchParams({
      action: 'query',
      list: 'allusers',
      format: 'json',
      augroup: this.groupHierarchy.join("|"),
      auprop: 'groups',
      aulimit: this.reqLimit,
      maxage: this.maxage,
      ...w,
    })
    const url = mw.config.get("wgServer") + "/w/api.php?" + params.toString()
    console.log(url)
    return fetch(url)
  },

  getData_mwApi(w = {}) {
    return (new mw.Api()).get({
      action: 'query',
      list: 'allusers',
      format: 'json',
      augroup: this.groupHierarchy,
      auprop: 'groups',
      aulimit: this.reqLimit,
      maxage: this.maxage,
      ...w,
    })
  },

  addAttrs($content, w = {}) {
    const settings = window.staffhlSettings;
    // 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
    settings.getData(w).then(async data => {
      if (settings.fetch) {
        data = await data.json();
      }
      console.log(data.query.allusers);
      if (settings.skipLimit && data['continue']) {
        settings.addAttrs($content, { ...w, aufrom: data['continue'].aufrom })
      }
      const links = $('.mw-body a.mw-userlink').get()
      console.log(links)
      links.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(' '))
        }
      })
    })
  }
  /*
  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, '')
    }
  }
  */
}

if (window.staffhlSettings.condition()) {
  if (window.staffhlSettings.fetch) {
    window.staffhlSettings.getData = window.staffhlSettings.getData_fetch
  } else {
    window.staffhlSettings.getData = window.staffhlSettings.getData_mwApi
  }
  mw.hook('wikipage.content').add(window.staffhlSettings.addAttrs)
  //window.staffhlSettings.addAttrs($content)
}