MediaWiki:Gadget-Geo.js:修订间差异

MediaWiki系统消息页面
(Git 版本 4c82224: 代码仓库同步更新)
 
(导入1个版本:​[页面文字原许可:CC BY-SA 4.0])
(没有差异)

2023年3月30日 (四) 16:50的版本

"use strict";

/* <nowiki> */
/**
 * SPDX-License-Identifier: GPL-2.0-or-later
 * _addText: '{{Gadget Header|license=GPLv2+}}'
 *
 * @source <github.com/wikimedia/mediawiki-extensions-CentralNotice/blob/5ac5d25f1a6ed1fa5b35bdc6f0eca209bad4cb91/resources/subscribing/ext.centralNotice.geoIP.js>
 * @dependency mediawiki.storage
 */
(function ($, mw) {
  if (window.Geo) {
    return;
  }
  var cName = "GeoIP";
  var geoPromise;

  /**
   * Parse geo data in cValue and return an object with properties from
   * the fields therein. Returns null if the value couldn't be parsed or
   * doesn't contain location data.
   *
   * The storage item will look like one of the following:
   * - "CN-SH-Shanghai"
   * - "CN-SH-"
   * - "CN--"
   * - "--"
   *
   * @param {string} cValue
   * @return {?Object}
   */
  var parseCValue = function parseCValue(cValue) {
    // TODO Verify that these Regexes are optimal. (Why no anchors? Why the
    // semicolon in the last group?)
    // Parse storage item
    var matches = cValue.match(/([^-]*)-([^-]*)-([^-]*)/);

    // No matches...? Boo, no data.
    if (!matches) {
      return null;
    }

    // There was no info found if there's no country field, or if it's
    // empty
    if (typeof matches[1] !== "string" || matches[1].length === 0) {
      return null;
    }

    // Return a juicy Geo object
    return {
      country: matches[1],
      region: matches[2],
      city: matches[3]
    };
  };

  /**
   * Request geo data and store it in the local storage
   *
   * @param {Object} geo
   */
  var storeGeoInStorage = function storeGeoInStorage() {
    $.ajax({
      url: "https://geo.qiuwen.net.cn"
    }).done(function (data) {
      var parts = [data.country || "", data.region || "", data.city || ""];
      var cValue = parts.join("-");
      mw.storage.set(cName, cValue, 3600); // 1 hour

      // Return Geo object
      return parseCValue(cValue);
    });
  };

  /**
   * Public geoIP object
   */
  mw.geoIP = {
    /**
     * Don't call this function! It is only exposed for tests.
     *
     * Set a promise that resolves with geo. First try to get data from the
     * GeoIP storage. If that fails, and if a background lookup callback
     * module is configured, try the background lookup.
     *
     * @private
     */
    makeGeoWithPromise: function makeGeoWithPromise() {
      var cValue = mw.storage.get(cName);
      var geo;

      // Were we able to read the storage?
      if (!cValue) {
        geo = storeGeoInStorage();
      } else {
        geo = parseCValue(cValue);
      }

      // All good? Resolve with geo and get outta here.
      if (geo) {
        geoPromise = $.Deferred().resolve(geo).promise();
        return;
      }
      geoPromise = $.Deferred().reject().promise();
    },
    /**
     * Returns a promise that resolves with geo when it's available. While
     * it's usually available right away, it may not be if a background
     * call is performed.
     *
     * @return {jQuery.Promise}
     */
    getPromise: function getPromise() {
      return geoPromise;
    }
  };
  mw.geoIP.makeGeoWithPromise();
  geoPromise.done(function (geo) {
    window.Geo = geo;
  });
})(jQuery, mediaWiki);

/* </nowiki> */