js2ts: diplomacy

- select2 관련 문제 해결?
This commit is contained in:
2021-08-30 00:27:04 +09:00
parent 604b1557e8
commit a6ff951c98
4 changed files with 534 additions and 5 deletions
+1 -4
View File
@@ -49,10 +49,7 @@ var permissionLevel = <?=$permission?>; //
</script>
<?=WebUtil::printJS('../d_shared/common_path.js')?>
<?=WebUtil::printJS('dist_js/vendors.js')?>
<?=WebUtil::printJS('dist_js/common.js')?>
<?=WebUtil::printJS('../e_lib/select2/select2.full.min.js')?>
<!--<?=WebUtil::printJS('../e_lib/tui.editor/tui-editor-Editor-all.min.js')?>-->
<?=WebUtil::printJS('js/diplomacy.js')?>
<?=WebUtil::printJS('dist_js/diplomacy.js')?>
</head>
<body>
+36 -1
View File
@@ -20,7 +20,7 @@ export type GeneralListResponse = {
result: true,
list: [
number,
string, 0|1,
string, 0 | 1,
number, number, string,
string, string, string,
string, string | null,
@@ -31,4 +31,39 @@ export type GeneralListResponse = {
number, number
][],
token: Record<number, number>,
}
export type NationLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export const NationLevelText: Record<NationLevel, string> = {
0: '방랑군',
1: '호족',
2: '군벌',
3: '주자사',
4: '주목',
5: '공',
6: '왕',
7: '황제',
}
export type CityLevel = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
export const CityLevelText: Record<CityLevel, string> = {
1: '수',
2: '진',
3: '관',
4: '이',
5: '소',
6: '중',
7: '대',
8: '특'
}
export type NationStaticItem = {
nation: number,
name: string,
color: string,
type: string,
level: NationLevel,
capital: number,
gennum: number,
power: number,
}
+496
View File
@@ -0,0 +1,496 @@
import $ from 'jquery';
import { unwrap_any } from './util/unwrap_any';
import axios from 'axios';
import { isBrightColor } from './common_legacy';
import { setAxiosXMLHttpRequest } from './util/setAxiosXMLHttpRequest';
import { isString } from 'lodash';
import { convertFormData } from './util/convertFormData';
import { InvalidResponse, NationStaticItem } from './defs';
import { escapeHtml } from './legacy/escapeHtml';
import { nl2br } from './util/nl2br';
import { unwrap } from './util/unwrap';
import { exportWindow } from './util/exportWindow';
import Popper from 'popper.js';
exportWindow(Popper, 'Popper');
import 'bootstrap';
import 'select2/dist/js/select2.full.js'
import { LoadingData } from 'select2';
declare const permissionLevel: number;
let myNationID: number | undefined;
type LetterNationTarget = {
nationID: number,
nationName: string,
nationColor: string,
}
type LetterFullTarget = LetterNationTarget & {
nationID: number,
nationName: string,
nationColor: string,
generalName: string,
generalIcon: string,
}
type LetterState = 'proposed' | 'activated' | 'cancelled' | 'replaced';
type LetterItem = {
no: number,
src: LetterFullTarget,
dest: LetterNationTarget | LetterFullTarget,
prev_no: number | null,
state: LetterState,
state_opt: 'try_destroy_src' | 'try_destroy_dest' | null,
brief: string,
detail: string,
date: string,
}
type LetterResponse = {
result: true,
nations: Record<number, NationStaticItem>,
letters: Record<number, LetterItem>,
myNationID: number,
}
const stateText: Record<LetterState, string> = {
'proposed': '제안됨',
'activated': '승인됨',
'cancelled': '거부됨',
'replaced': '대체됨',
};
const stateOptionText: Record<NonNullable<LetterItem['state_opt']>, string> = {
'try_destroy_src': '송신측의 파기 요청',
'try_destroy_dest': '수신측의 파기 요청',
}
async function submitLetter(e: JQuery.Event): Promise<void> {
e.preventDefault();
const $brief = $('#inputBrief');
const $detail = $('#inputDetail');
const $prevNo = $('#inputPrevNo');
const $destNation = $('#inputDestNation');
const brief = $.trim(unwrap_any<string>($brief.val()));
const detail = $.trim(unwrap_any<string>($detail.val()));
let prevNo = $prevNo.val() as number | undefined;
const destNation = unwrap_any<number>($destNation.val());
if (prevNo !== undefined && prevNo < 1) {
prevNo = undefined;
}
console.log(brief);
if (!brief) {
return;
}
$brief.val('');
$detail.val('');
let result: InvalidResponse;
try {
const response = await axios({
url: 'j_diplomacy_send_letter.php',
responseType: 'json',
method: 'post',
data: convertFormData({
brief: brief,
detail: detail,
destNation: destNation,
prevNo: prevNo ?? null,
})
});
result = response.data;
if (!result.result) {
throw result.reason;
}
}
catch (e) {
console.error(e);
alert(`외교 서신을 보내는데 실패했습니다: ${e}`);
return;
}
alert('전송했습니다.');
location.reload();
}
async function repondLetter(letterNo: number, isAgree: boolean, reason: string | null): Promise<void> {
let result: InvalidResponse;
try {
const response = await axios({
url: 'j_diplomacy_respond_letter.php',
responseType: 'json',
method: 'post',
data: convertFormData({
letterNo: letterNo,
isAgree: isAgree,
reason: reason,
})
});
result = response.data;
if (!result.result) {
throw result.reason;
}
}
catch (e) {
console.error(e);
alert(`응답을 실패했습니다: ${e}`);
return;
}
if (isAgree) {
alert('승인했습니다.');
}
else {
alert('거부했습니다.');
}
location.reload();
}
async function rollbackLetter(letterNo: number) {
let result: InvalidResponse;
try {
const response = await axios({
url: 'j_diplomacy_rollback_letter.php',
responseType: 'json',
method: 'post',
data: convertFormData({
letterNo: letterNo,
})
});
result = response.data;
if (!result.result) {
throw result.reason;
}
}
catch (e) {
console.error(e);
alert(`회수를 실패했습니다: ${e}`);
return;
}
alert('회수 했습니다.');
location.reload();
}
async function destroyLetter(letterNo: number) {
let result: InvalidResponse | {
result: true,
state: LetterState
};
try {
const response = await axios({
url: 'j_diplomacy_destroy_letter.php',
responseType: 'json',
method: 'post',
data: convertFormData({
letterNo: letterNo,
})
});
result = response.data;
if (!result.result) {
throw result.reason;
}
}
catch (e) {
console.error(e);
alert(`회수를 실패했습니다: ${e}`);
return;
}
if (result.state == 'activated') {
alert('파기를 요청 했습니다.');
}
else {
alert('파기 되었습니다.');
}
location.reload();
}
function drawLetter(letterObj: LetterItem) {
if (letterObj.state == 'cancelled') {
//TODO: 취소되거나, 대체된 문서도 보여줄 방법을 찾아볼 것
return;
}
console.log(letterObj);
const $letterFrame = $('#letterTemplate > .letterFrame');
const srcColorFormat = {
'background-color': letterObj.src.nationColor,
'color': isBrightColor(letterObj.src.nationColor) ? '#000000' : '#ffffff'
};
const destColorFormat = {
'background-color': letterObj.dest.nationColor,
'color': isBrightColor(letterObj.dest.nationColor) ? '#000000' : '#ffffff'
};
const targetNation = letterObj.src.nationID == myNationID ? letterObj.dest : letterObj.src;
const targetColor = letterObj.src.nationID == myNationID ? destColorFormat : srcColorFormat;
const $letter = $letterFrame.clone();
if (letterObj.state == 'replaced') {
$letter.hide();
}
$letter.addClass('letterObj')
.data('no', letterObj.no)
.data('brief', letterObj.brief)
.data('detail', letterObj.detail)
.attr('id', 'letter_' + letterObj.no);
$letter.find('.letterHeader').css(targetColor);
$letter.find('.letterNationName').text(targetNation.nationName);
$letter.find('.letterDate').text(letterObj.date);
$letter.find('.letterNo').text('#' + letterObj.no);
$letter.find('.letterStatus').text(stateText[letterObj.state]);
if (letterObj.state_opt !== null) {
$letter.find('.letterStatusOpt').text(`(${unwrap(stateOptionText[letterObj.state_opt])})`);
}
if (letterObj.prev_no !== null) {
const $showPrev = $(`<a href="#">#${letterObj.prev_no}</a>`);
$showPrev.click(function () {
$('#letter_' + letterObj.prev_no).toggle();
})
$letter.find('.letterPrevNo').empty().append($showPrev);
}
else {
$letter.find('.letterPrevNo').text('신규');
}
$letter.find('.letterBrief').html(nl2br(escapeHtml(letterObj.brief)));
$letter.find('.letterDetail').html(nl2br(escapeHtml(letterObj.detail)));
$letter.find('.letterSrc .signerImg img.generalIcon').attr('src', letterObj.src.generalIcon);
$letter.find('.letterSrc .signerNation').text(letterObj.src.nationName).css(srcColorFormat);
$letter.find('.letterSrc .signerName').text(letterObj.src.generalName).css(srcColorFormat);
if ('generalName' in letterObj.dest) {
$letter.find('.letterDest .signerImg img.generalIcon').attr('src', letterObj.dest.generalIcon);
$letter.find('.letterDest .signerNation').text(letterObj.dest.nationName).css(destColorFormat);
$letter.find('.letterDest .signerName').text(letterObj.dest.generalName).css(destColorFormat);
}
if (letterObj.state == 'proposed' && letterObj.src.nationID != myNationID) {
$letter.find('.btnAgree').show().click(async function (e) {
e.preventDefault();
if (!confirm('승인하시겠습니까?')) {
return;
}
await repondLetter(letterObj.no, true, null);
});
$letter.find('.btnDisagree').show().click(async function (e) {
e.preventDefault();
let reason = prompt('거부하시겠습니까? (이유 [최대 50자])');
if (reason === null) {
return;
}
reason = reason.substr(0, 50);
await repondLetter(letterObj.no, false, reason);
});
}
if (letterObj.state == 'proposed' && letterObj.src.nationID == myNationID) {
$letter.find('.btnRollback').show().click(async function (e) {
e.preventDefault();
if (!confirm('회수하시겠습니까?')) {
return false;
}
await rollbackLetter(letterObj.no);
});
}
if (letterObj.state == 'activated') {
const $btnDestroy = $letter.find('.btnDestroy');
if ((letterObj.src.nationID == myNationID && letterObj.state_opt == 'try_destroy_src') ||
(letterObj.dest.nationID == myNationID && letterObj.state_opt == 'try_destroy_dest')) {
$btnDestroy.show().prop('disabled', true);
}
else {
$btnDestroy.show().click(async function (e) {
e.preventDefault();
if (!confirm('본 문서를 파기하겠습니까? (상호 동의 필요)')) {
return false;
}
await destroyLetter(letterObj.no);
})
}
}
$letter.find('.btnRenew').click(function () {
const $inputPrevNo = $('#inputPrevNo');
$inputPrevNo.val(letterObj.no);
$inputPrevNo.trigger('change');
})
$('#letters').prepend($letter);
}
function initNewLetterForm(lettersObj: LetterResponse) {
console.log(lettersObj);
const nationList: (NationStaticItem & { id: number, text: string })[] = [];
for (const nation of Object.values(lettersObj.nations)) {
nationList.push({
...nation,
id: nation.nation,
text: nation.name,
});
}
const $destNation = $('#inputDestNation').select2({
theme: 'bootstrap4',
placeholder: "",
language: "ko",
width: '300px',
containerCss: {
display: "inline-block !important;",
color: 'white !important'
},
data: nationList,
templateResult: colorNation,
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
const prevNoList: {
id: number,
text: string,
nation: null | number,
}[] = [{
id: 0,
text: '-새 문서-',
nation: null,
}];
for(const letterObj of Object.values(lettersObj.letters)){
if (letterObj.state == 'replaced' || letterObj.state == 'cancelled') {
continue;
}
const targetNation = letterObj.src.nationID == myNationID ? letterObj.dest : letterObj.src;
prevNoList.push({
id: letterObj.no,
text: `#${letterObj.no} <${targetNation.nationName}>`,
nation: targetNation.nationID
});
}
const $inputPrevNo = $('#inputPrevNo').select2({
theme: 'bootstrap4',
placeholder: "",
language: "ko",
width: '300px',
containerCss: {
display: "inline-block !important;",
color: 'white !important'
},
data: prevNoList,
containerCssClass: 'simple-select2-align-center bg-secondary text-secondary',
dropdownCssClass: 'simple-select2-align-center bg-secondary text-secondary',
});
$inputPrevNo.on('change', function () {
const data = $inputPrevNo.select2('data')[0] as unknown as typeof prevNoList[0];
console.log(data);
if (data.nation == null) {
$destNation.prop("disabled", false);
}
else {
$destNation.val(data.nation).prop("disabled", true);
const $targetLetter = $('#letter_' + data.id);
resizeTextarea($('#inputBrief').val($targetLetter.data('brief')));
resizeTextarea($('#inputDetail').val($targetLetter.data('detail')));
}
});
$('#btnSend').click(submitLetter);
$('#newLetter').show();
}
function drawLetters(lettersObj: LetterResponse) {
myNationID = lettersObj.myNationID;
if (permissionLevel == 4) {
initNewLetterForm(lettersObj);
$('.letterActionPlate').show();
}
$('.letterObj').detach();//첫 버전이니까 일괄 삭제 일괄 로드
for (const letter of Object.values(lettersObj.letters)) {
drawLetter(letter);
}
}
async function loadLetters(): Promise<LetterResponse> {
const response = await axios({
url: 'j_diplomacy_get_letter.php',
responseType: 'json',
method: 'post',
data: convertFormData({
})
});
const result: LetterResponse|InvalidResponse = response.data;
if(!result.result){
throw result.reason;
}
return result;
}
function colorNation(nationInfo: { id: number, text: string, color?: string } | LoadingData) {
if (!('color' in nationInfo)) {
return nationInfo.text;
}
if (!nationInfo.color) {
return nationInfo.text;
}
const fgColor = isBrightColor(nationInfo.color) ? '#000000' : '#ffffff';
const $nationForm = $('<div>' + nationInfo.text + '</div>').css({
'color': fgColor,
'background-color': nationInfo.color
});
return $nationForm;
}
function resizeTextarea($obj: JQuery<HTMLElement>) {
$obj.height(1).height($obj.prop('scrollHeight') + 12);
}
$(async function () {
setAxiosXMLHttpRequest();
$('textarea.autosize').on('keydown keyup', function () {
resizeTextarea($(this));
})
try {
const letters = await loadLetters();
drawLetters(letters);
}
catch (e) {
console.error(e);
if (isString(e)) {
alert(e);
}
else {
alert(`실패했습니다.`);
}
return;
}
});
+1
View File
@@ -35,6 +35,7 @@ module.exports = (env, argv) => {
extExpandCity: '@/extExpandCity.ts',
main: '@/main.ts',
dipcenter: '@/dipcenter.ts',
diplomacy: '@/diplomacy.ts',
//FORM 입력용, frontend 변경후 제거