// @ts-nocheck import scriptjs from "scriptjs"; import jsonp from "jsonp"; // import queryString from 'query-string'; import { zipObject } from "./lodash-alt"; export const PANE_LEVEL_KEYS = ["country", "province", "city", "area", "town"]; export const ADDRTREE_ROOT_NAME = "GLOBAL_MAGIC_PLANET_EARTH"; export const ADDRTREE_ROOT_KEY = "0"; export const ADDRTREE_ROOT_LEVEL_KEY = "GLOBAL_MAGIC_PLANET_EARTH_LEVEL_KEY"; export const CACHE_COMP_VERSION = 11; export const PANE_LEVELS = ["province", "city", "area", "town"]; export const PANE_ATTRIBUTES = { country: { index: 0, field: "country", title: "国家" }, province: { index: 1, field: "province", title: "省" }, city: { index: 2, field: "city", title: "市" }, area: { index: 3, field: "area", title: "区" }, town: { index: 4, field: "town", title: "街道" }, }; function stringify(obj) { const arr = []; const keys = Object.keys(obj); keys.forEach((key) => { if (obj[key] instanceof Array) { obj[key].forEach((value) => { arr.push(`${key}=${encodeURIComponent(value)}`); }); } else { arr.push(`${key}=${encodeURIComponent(obj[key])}`); } }); return arr.join("&"); } export function topologySort(allNodesSet) { const nodesWithoutParent = []; const unsortedNodeKeys = Object.keys(allNodesSet); while (unsortedNodeKeys.length) { const thisNodeKey = unsortedNodeKeys.pop(); const thisNode = allNodesSet[thisNodeKey]; if (thisNode.parent !== null) { if (allNodesSet[thisNode.parent]) { allNodesSet[thisNode.parent].children.push(thisNode); } } else { nodesWithoutParent.push(thisNode); } } return nodesWithoutParent; } export function preprocessRawAddressData( params, rawData, ignored = {}, isLeaf = false ) { const allNodesSet = {}; const keys = Object.keys(rawData); for (let i = 0, j = keys.length; i < j; i++) { const rawNodeID = keys[i]; if (!Object.prototype.hasOwnProperty.call(ignored, rawNodeID)) { const rawNode = rawData[rawNodeID]; const processed = { id: rawNodeID, parent: rawNode[1], nameZh: rawNode[0], namePy: rawNode[2], nameEn: rawNode[3] || "", // result of output_address_town has no [3] value: rawNodeID, label: rawNode[0], }; if (isLeaf) { processed.isLeaf = true; } else { processed.children = []; } allNodesSet[rawNodeID] = processed; } } return allNodesSet; } export function loadAddressData(params) { const { ignored, dataOverride, preprocessor } = params; const ignoredMap = ignored ? zipObject(ignored, new Array(ignored.length).fill(true)) : null; return new Promise((resolve) => { scriptjs(params.addressURL, () => { const rawDataOrg = window.tdist; const rawData = Object.create(null); const mergeData = (dict, strict) => Object.keys(dict).forEach((k) => { if (Array.isArray(dict[k])) { rawData[k] = [...dict[k]]; } else if (strict) { // eslint-disable-next-line console.warn("Address: invalid value for id ", k); } }); mergeData(rawDataOrg, false); if (dataOverride) { mergeData(dataOverride, true); } if (typeof preprocessor === "function") { preprocessor(rawData); } rawData[ADDRTREE_ROOT_KEY] = [ ADDRTREE_ROOT_NAME, null, ADDRTREE_ROOT_NAME, ADDRTREE_ROOT_NAME, ]; const allNodesSet = preprocessRawAddressData(params, rawData, ignoredMap); const nodesWithoutParent = topologySort(allNodesSet); nodesWithoutParent.forEach(function sortChildrenRecursive(node) { node.children.forEach(sortChildrenRecursive); node.children.sort( (lhs, rhs) => parseInt(lhs.id, 10) - parseInt(rhs.id, 10) ); }); nodesWithoutParent.forEach( function labelLevel(level, node) { /* eslint-disable */ node.level = level; /* eslint-disable */ node.children.forEach(labelLevel.bind(null, level + 1)); }.bind(null, -1) ); // add 'levelKey' attribute nodesWithoutParent.forEach( (node) => (node.levelKey = ADDRTREE_ROOT_LEVEL_KEY) ); nodesWithoutParent.forEach( function labelLevelKey(level, node) { if (level >= 0) { node.levelKey = PANE_LEVEL_KEYS[level]; } node.children.forEach(labelLevelKey.bind(null, level + 1)); }.bind(null, -1) ); // add 'parentNode' attribute nodesWithoutParent.forEach( function labelParentNode(parentNode, node) { node.parentNode = parentNode; node.children.forEach(labelParentNode.bind(null, node)); }.bind(null, null) ); nodesWithoutParent.forEach(function leaveifyChildlessCountry(node) { if (node.levelKey === "country" && !node.children.length) { (node.isLeaf = true), (node.children = undefined); } else { node.children.forEach(leaveifyChildlessCountry); } }); nodesWithoutParent.forEach( function markCountry(country, node) { if (country === null) { node.ofCountry = "0"; } else { node.ofCountry = country; } if (node.children) { if (node.levelKey == "country") { node.children.forEach(markCountry.bind(null, node.id)); } else { node.children.forEach(markCountry.bind(null, country)); } } }.bind(null, null) ); nodesWithoutParent.forEach(function annotatePy(node) { node.namePy = node.namePy.toLowerCase(); node.namePyJoined = node.namePy.replace(/\ /g, ""); node.namePyAbbr = (node.namePy.match(/\b([a-zA-Z])/g) || []).join(""); if (node.children) { node.children.forEach(annotatePy); } }); resolve({ countryList: [].concat( ...nodesWithoutParent.map((n) => n.children.map((node) => ({ value: node.value, label: node.label })) ) ), allNodesSet, addressTree: nodesWithoutParent[0], // [0].children }); }); }); } export function selectionToChain(value) { return PANE_LEVEL_KEYS.map((key) => value[key]) // keys array, must be in order .filter((v) => !!v); } export function nodeChainFromNode(node) { return (!node.parentNode ? [] : nodeChainFromNode(node.parentNode)).concat( node ); } export function foldNodeChainToSelection(nodeChain) { const ret = {}; nodeChain.forEach((node) => { node && node.levelKey ? (ret[node.levelKey] = node.id) : ""; }); return ret; } export function loadTownData(reqParams, node) { // output_address_town returns a huge blob of useless data // when used against a country if (node.levelKey === "country") { return Promise.resolve([]); } const selectionChain = nodeChainFromNode(node).slice(1); const params = {}; for (let i = 0; i < selectionChain.length; i++) { params[`l${i}`] = selectionChain[i].id; } return new Promise((resolve, reject) => { const url = `${reqParams.townURL}?${stringify(params)}`; jsonp(url, (err, data) => { if (err) { return reject(err); } // TODO: throw the Right error if (!data.success) { return reject(data); } const rawData = data.result; const townsSet = preprocessRawAddressData( reqParams, rawData, {} /* ignored */, true ); const townsList = Object.keys(townsSet).map((key) => townsSet[key]); townsList.sort((lhs, rhs) => parseInt(lhs.id) - parseInt(rhs.id)); // townsList.forEach(n => (n.level = node.level + 1)); townsList.forEach((n) => (n.level = 4)); townsList.forEach((n) => (n.levelKey = "town")); townsList.forEach((n) => (n.parentNode = node)); resolve(townsList); }); }); } export function traceTownParents({ parentURL }, divisionId, allNodesSet) { return new Promise((resolve, reject) => { const url = `${parentURL}?${stringify({ divisionId })}`; jsonp(url, (err, data) => { if (err) { return reject(err); } const ret = {}; Object.keys(data).forEach( (key) => data[key] && (ret[key] = data[key].id) ); if (!ret.hasOwnProperty("country")) { ret.country = "1"; } resolve(selectionToChain(ret)); }); }); } export function defaultTextSerializer(nodeChain) { return nodeChain.map((x) => x.nameZh).join(""); } export function standardValueEqual(lhs, rhs) { for (const key in lhs) { if (!(key in rhs) || lhs[key] != rhs[key]) { return false; } } for (const key in rhs) { if (!(key in lhs) || lhs[key] != rhs[key]) { return false; } } return true; } export const addressTreeOfSet = (allNodesSet) => allNodesSet[ADDRTREE_ROOT_KEY]; export const delay = (n = 0) => new Promise((resolve, reject) => setTimeout(() => resolve(), n)); export const id = (v) => v;