js2ts: chiefCenter

- common: unwrap_any
- jQuery export 수정
- axios로 변경
- moment -> luxon
This commit is contained in:
2021-08-16 01:06:17 +09:00
parent aac6632f4b
commit bc218b73e1
23 changed files with 376 additions and 214 deletions
+39
View File
@@ -0,0 +1,39 @@
type JqueryRedirectOpts = {
url: string,
values?: Record<string, string | number | string[] | boolean>,
method?: 'GET' | 'POST',
target?: string,
traditional?: boolean
redirectTop?: boolean,
}
interface JQueryStatic {
/**
* jQuery Redirect
* @param {string} url - Url of the redirection
* @param {Object} values - (optional) An object with the data to send. If not present will look for values as QueryString in the target url.
* @param {string} method - (optional) The HTTP verb can be GET or POST (defaults to POST)
* @param {string} target - (optional) The target of the form. If you set "_blank" will open the url in a new window.
* @param {boolean} traditional - (optional) This provides the same function as jquery's ajax function. The brackets are omitted on the field name if its an array. This allows arrays to work with MVC.net among others.
* @param {boolean} redirectTop - (optional) If its called from a iframe, force to navigate the top window.
*/
redirect(
url: string,
values?: Record<string, string | number | string[] | boolean>,
method?: 'GET' | 'POST',
target?: string, traditional?:
boolean, redirectTop?: boolean
): void;
/**
* jQuery Redirect
* @param {string} opts - Options object
* @param {string} opts.url - Url of the redirection
* @param {Object} opts.values - (optional) An object with the data to send. If not present will look for values as QueryString in the target url.
* @param {string} opts.method - (optional) The HTTP verb can be GET or POST (defaults to POST)
* @param {string} opts.target - (optional) The target of the form. "_blank" will open the url in a new window.
* @param {boolean} opts.traditional - (optional) This provides the same function as jquery's ajax function. The brackets are omitted on the field name if its an array. This allows arrays to work with MVC.net among others.
* @param {boolean} opts.redirectTop - (optional) If its called from a iframe, force to navigate the top window.
*/
redirect(opt: JqueryRedirectOpts): void;
}
+256
View File
@@ -0,0 +1,256 @@
import axios from 'axios';
import $ from 'jquery';
import { range } from 'lodash';
import { DateTime } from 'luxon';
import { errUnknown, getNpcColor } from './common_legacy';
import { InvalidResponse } from './defs';
import { unwrap } from './util';
import { convertFormData } from './util/convertFormData';
import { unwrap_any } from "./util/unwrap_any";
declare const maxChiefTurn: number;
type TurnDOMObj = {
turnTime: JQuery<HTMLElement>,
turnPad: JQuery<HTMLElement>,
turnText: JQuery<HTMLElement>
};
type TableObj = {
btns: JQuery<HTMLElement>;
[key: number]: {
officerLevelText: JQuery<HTMLElement>,
name: JQuery<HTMLElement>,
turn: TurnDOMObj[],
}
}
type ChiefResponse = InvalidResponse | {
result: true,
date: string,
nationTurnBrief: {
name:string|null,
turnTime:string|null,
officerLevelText:string,
npcType:number,
turn:string
}[],
isChief: boolean,
turnTerm: number
}
let filledChiefList: Record<number, boolean> = {};
let chiefTableObj: TableObj = undefined as unknown as TableObj;//TODO: 매우 지저분하다. class 기반으로 고치던가 할 것
/*
function clearTable() {
$('.chiefLevelText').html('-');
$('.chiefTurnTime, .chiefTurnText, .chiefName').html('&nbsp;');
}
*/
function genChiefTableObj(): TableObj {
const objTable: TableObj = {
btns: $('#turnPush,#turnPull,#setCommand')
};
for (const chiefIdx of range(5, 13)) {
const $plate = $('#chief_{0}'.format(chiefIdx));
const $officerLevelText = $plate.find('.chiefLevelText');
const $name = $plate.find('.chiefName');
const turn: TurnDOMObj[] = [];
for (const turnIdx of range(maxChiefTurn)) {
const $turn = $plate.find('.turn{0}'.format(turnIdx));
const $turnTime = $turn.find('.chiefTurnTime');
const $turnPad = $turn.find('.chiefTurnPad');
const $turnText = $turn.find('.chiefTurnText');
turn.push({ turnTime: $turnTime, turnPad: $turnPad, turnText: $turnText });
}
objTable[chiefIdx] = {
officerLevelText: $officerLevelText,
name: $name,
turn: turn
};
}
return objTable;
}
function clearChief(chiefIdx: number): void {
const $plate = $('#chief_{0}'.format(chiefIdx));
$plate.find('.chiefLevelText').html('-');
$plate.find('.chiefTurnTime, .chiefTurnText, .chiefName').html('&nbsp;');
}
async function reloadTable() {
const data: ChiefResponse = await (async () => {
try {
const response = await axios({
url: 'j_getChiefTurn.php',
responseType: 'json'
});
return response.data;
}
catch (e) {
console.error(e);
errUnknown();
}
})();
if (!data.result) {
alert(data.reason);
return;
}
const turnTerm = data.turnTerm;
const tmpFilledChiefList:Record<number, boolean> = {};
if (data.isChief) {
chiefTableObj.btns.css('visibility', 'visible');
}
else {
chiefTableObj.btns.css('visibility', 'hidden');
}
$.each(data.nationTurnBrief, function (chiefIdx, chiefInfo) {
tmpFilledChiefList[chiefIdx] = true;
filledChiefList[chiefIdx] = true;
const plateObj = chiefTableObj[chiefIdx];
if (chiefInfo.name) {
const $name = $('<span>{0}</span>'.format(chiefInfo.name));
const nameColor = getNpcColor(chiefInfo.npcType);
if (nameColor) {
$name.css('color', nameColor);
}
plateObj.name.empty().append($name);
}
else {
plateObj.name.html('');
}
plateObj.officerLevelText.text(chiefInfo.officerLevelText);
let turnTimeObj: DateTime|undefined;
if (chiefInfo.turnTime) {
turnTimeObj = DateTime.fromSQL(chiefInfo.turnTime);
}
const turnList = plateObj.turn;
$.each(chiefInfo.turn, function (turnIdx, turnText) {
if (turnTimeObj) {
turnList[turnIdx].turnTime.text(turnTimeObj.toFormat('HH:mm'));
}
else {
turnList[turnIdx].turnTime.text('');
}
turnList[turnIdx].turnText.html(turnText).css('font-size', '13px');
const oWidth = unwrap(turnList[turnIdx].turnPad.innerWidth());
const iWidth = unwrap(turnList[turnIdx].turnText.outerWidth());
if (iWidth > oWidth * 0.95) {
const newFontSize = 13 * oWidth / iWidth * 0.9;
turnList[turnIdx].turnText.css('font-size', '{0}px'.format(newFontSize));
}
if (turnTimeObj) {
turnTimeObj = turnTimeObj.plus({'minutes': turnTerm});
}
});
});
for (const idx of range(5, 13)) {
if (idx in tmpFilledChiefList) {
continue;
}
if (idx in filledChiefList) {
clearChief(idx);
}
}
filledChiefList = tmpFilledChiefList;
}
async function reserveTurn(turnList: number[], command: string) {
console.log(turnList, command);
try{
const response = await axios({
url: 'j_set_chief_command.php',
responseType:'json',
method: 'post',
data: convertFormData({
turnList,
action: command
})
});
const data: InvalidResponse = response.data;
if (!data.result) {
alert(data.reason);
}
await reloadTable();
}
catch(e){
console.error(e);
errUnknown();
}
}
async function pushTurn(turnCnt: number) {
try {
const response = await axios({
url: 'j_chief_turn.php',
responseType: 'json',
method: 'post',
data: convertFormData({
amount: turnCnt
})
});
const data = response.data;
if (!data.result) {
alert(data.reason);
}
await reloadTable();
}
catch (e) {
console.error(e);
errUnknown();
}
}
jQuery(function ($) {
chiefTableObj = genChiefTableObj();
void reloadTable();
$('#reloadTable').on('click', reloadTable);
$('#setCommand').on('click', function () {
const turnList = unwrap_any<string[]>($('#chiefTurnSelector').val()).map(function (v) { return parseInt(v); });
const $command = $('#chiefCommandList option:selected');
if ($command.data('reqarg')) {
$.redirect(
"b_processing.php", {
command: unwrap($command.val()),
turnList: turnList.join('_'),
is_chief: true
}, "GET");
}
else {
void reserveTurn(turnList, unwrap_any<string>($command.val()));
}
return false;
});
$('#turnPush').on('click', function () {
void pushTurn(1);
return false;
});
$('#turnPull').on('click', function () {
void pushTurn(-1);
return false;
});
})
+2 -5
View File
@@ -1,7 +1,7 @@
import { activeFlip, escapeHtml, isInt, mb_strwidth, mb_strimwidth, convertDictById, convertSet, hexToRgb, isBrightColor, convColorValue, numberWithCommas, linkifyStrWithOpt, TemplateEngine, getIconPath, combineObject, combineArray, activeFlipItem, errUnknown, errUnknownToast, quickReject, nl2br, getNpcColor, initTooltip } from "./common_legacy";
import jQuery from "jquery";
window.jQuery = jQuery;
window.$ = jQuery;
jQuery(function ($) {
initTooltip();
@@ -68,9 +68,6 @@ declare global {
}
}
window.$ = jQuery;
window.jQuery = jQuery;
window.escapeHtml = escapeHtml;
window.isInt = isInt;
window.mb_strwidth = mb_strwidth;
+8 -3
View File
@@ -3,6 +3,11 @@ import { unwrap } from "./util";
import jQuery from "jquery";
import 'bootstrap';
import axios from "axios";
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
//TODO: X-Requested-With 믿지 말자.
/**
* <>& 등을 html에서도 그대로 보이도록 escape주는 함수
* @see https://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
@@ -122,12 +127,12 @@ export function convertSet<K extends string | number>(arr: ArrayLike<K>): Record
declare global {
interface String {
format(...args: string[]): string;
format(...args: (string | number)[]): string;
}
}
String.prototype.format = function (...args: string[]) {
String.prototype.format = function (...args: (string | number)[]) {
return this.replace(/{(\d+)}/g, function (match, number) {
return (typeof args[number] != 'undefined') ? args[number] : match;
return (typeof args[number] != 'undefined') ? args[number].toString() : match;
});
};
+4
View File
@@ -0,0 +1,4 @@
export type InvalidResponse = {
result: false;
reason: string;
}
+5 -5
View File
@@ -6,7 +6,7 @@ import "../scss/troop.scss";
jQuery(function($){
//btnJoinTroop, btnLeaveTroop, btnKickTroop, btnCreateTroop, btnChangeTroopName
$('#btnLeaveTroop').click(function(e){
$('#btnLeaveTroop').click(function(){
if(!confirm("정말 부대를 탈퇴하시겠습니까?")){
return false;
}
@@ -29,7 +29,7 @@ jQuery(function($){
return false;
});
$('#btnCreateTroop').click(function(e){
$('#btnCreateTroop').click(function(){
$.post({
url:'j_troop.php',
dataType:'json',
@@ -50,7 +50,7 @@ jQuery(function($){
return false;
});
$('#btnChangeTroopName').click(function(e){
$('#btnChangeTroopName').click(function(){
$.post({
url:'j_troop.php',
dataType:'json',
@@ -71,7 +71,7 @@ jQuery(function($){
return false;
});
$('#btnKickTroop').click(function(e){
$('#btnKickTroop').click(function(){
$.post({
url:'j_troop.php',
dataType:'json',
@@ -92,7 +92,7 @@ jQuery(function($){
return false;
});
$('#btnJoinTroop').click(function(e){
$('#btnJoinTroop').click(function(){
$.post({
url:'j_troop.php',
dataType:'json',
+1 -1
View File
@@ -1,5 +1,5 @@
type ErrType<T> = { new(msg?: string): T }
type Nullable<T> = T | null | undefined
export type Nullable<T> = T | null | undefined
export class RuntimeError extends Error {
public name = 'RuntimeError';
+32
View File
@@ -0,0 +1,32 @@
import { isArray, isString, isNumber, isBoolean } from "lodash";
export function convertFormData(values: Record<string, number[]|string[]|boolean[]|number|string|boolean>): FormData{
const formData = new FormData();
const simpleConv = (v: unknown):string=>{
if(isString(v)){
return v;
}
if(isNumber(v)){
return v.toString();
}
if(isBoolean(v)){
return v?'true':'false';
}
throw new TypeError('지원하지 않는 formData Type');
}
for(const [key, value] of Object.entries(values)){
if(isArray(value)){
const arrKey = `${key}[]`;
for(const subValue of value){
formData.append(arrKey, simpleConv(subValue));
}
continue;
}
formData.append(key, simpleConv(value));
}
return formData;
}
+9
View File
@@ -0,0 +1,9 @@
import { Nullable, NotNullExpected } from "../util";
export function unwrap_any<T>(result: Nullable<unknown>): T {
if (result === null || result === undefined) {
throw new NotNullExpected();
}
return result as T;
}