로그인 form draw 예시

This commit is contained in:
2020-06-26 23:31:45 +09:00
parent 40968b301a
commit 3c18666080
5 changed files with 1219 additions and 1108 deletions
+131 -130
View File
@@ -1,131 +1,132 @@
body, html{
height: 100%;
background-repeat: no-repeat;
}
.main{
margin-top: 70px;
}
h1.title {
font-size: 50px;
font-family: 'Passion One', cursive;
font-weight: 400;
}
hr{
width: 10%;
/*color: #fff;*/
}
.form-group{
margin-bottom: 15px;
}
label{
margin-bottom: 15px;
}
input,
input::-webkit-input-placeholder {
font-size: 11px;
padding-top: 3px;
}
.main-login{
/*background-color: #fff;*/
/* shadows and rounded borders */
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}
.main-center{
margin-top: 30px;
margin: 0 auto;
max-width: 330px;
padding: 40px 40px;
}
.login_btn_group{
margin-top: 5px;
}
.login-register{
font-size: 11px;
text-align: center;
}
.col-form-label{
text-align:center;
}
.terms{
max-height: 200px; overflow-y: auto;
}
.terms pre{
width:100%;
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
.vertical-center {
min-height: 100%; /* Fallback for browsers do NOT support vh unit */
min-height: 100vh; /* These two lines are counted as one :-) */
display: flex;
align-items: center;
}
.full-content {
position:fixed;
left:0;
top:0;
width:100%;
height:100%;
margin:0;
padding:0;
z-index:800;
}
#login_card{
z-index:801;
}
#btn_kakao_login{
cursor: pointer;
height:46px;
width:116px;
background-color: transparent;
color:transparent;
border:0;
background-size: 100%; /* To fill the dimensions of container (button), or */
background-repeat: no-repeat;
background-position: bottom center;
margin-top:5px;
background-image:url('../oauth_kakao/kakao_login_join.png');
}
#btn_kakao_login:hover {
background-image:url('../oauth_kakao/kakao_login_join_ov.png');
}
#bottom_box{
position:fixed;
bottom:0;
width:100%;
left:0;
}
#bottom_box .container{
text-align:center;
body,
html {
height: 100%;
background-repeat: no-repeat;
}
.main {
margin-top: 70px;
}
h1.title {
font-size: 50px;
font-family: 'Passion One', cursive;
font-weight: 400;
}
hr {
width: 10%;
/*color: #fff;*/
}
.form-group {
margin-bottom: 15px;
}
label {
margin-bottom: 15px;
}
input,
input::-webkit-input-placeholder {
font-size: 11px;
padding-top: 3px;
}
.main-login {
/*background-color: #fff;*/
/* shadows and rounded borders */
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}
.main-center {
margin-top: 30px;
margin: 0 auto;
max-width: 330px;
padding: 40px 40px;
}
.login_btn_group {
margin-top: 5px;
}
.login-register {
font-size: 11px;
text-align: center;
}
.col-form-label {
text-align: center;
}
.terms {
max-height: 200px;
overflow-y: auto;
}
.terms pre {
width: 100%;
white-space: pre-wrap;
/* Since CSS 2.1 */
white-space: -moz-pre-wrap;
/* Mozilla, since 1999 */
white-space: -pre-wrap;
/* Opera 4-6 */
white-space: -o-pre-wrap;
/* Opera 7 */
word-wrap: break-word;
/* Internet Explorer 5.5+ */
}
.vertical-center {
min-height: 100%;
/* Fallback for browsers do NOT support vh unit */
min-height: 100vh;
/* These two lines are counted as one :-) */
display: flex;
align-items: center;
}
#login_card {
z-index: 801;
}
#btn_kakao_login {
cursor: pointer;
height: 46px;
width: 116px;
background-color: transparent;
color: transparent;
border: 0;
background-size: 100%;
/* To fill the dimensions of container (button), or */
background-repeat: no-repeat;
background-position: bottom center;
margin-top: 5px;
background-image: url('../oauth_kakao/kakao_login_join.png');
}
#btn_kakao_login:hover {
background-image: url('../oauth_kakao/kakao_login_join_ov.png');
}
#bottom_box .container {
text-align: center;
}
.btn-group-xs>.btn,
.btn-xs {
padding: .25rem .4rem;
font-size: .875rem;
line-height: .5;
border-radius: .2rem;
}
#running_map {
margin-top: 20px;
}
+6 -1
View File
@@ -54,7 +54,7 @@ $defaultPost = [
'showMe' => false,
];
$history = getGlobalHistoryLogRecent(15);
$history = formatHistoryToHTML(getGlobalHistoryLogRecent(10));
$rawMap = getWorldMap([
'year' => null,
'month' => null,
@@ -63,7 +63,12 @@ $rawMap = getWorldMap([
'showMe' => false,
]);
$db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env');
$mapTheme = $gameStor->map_theme ?? 'che';
$rawMap['history'] = $history;
$rawMap['theme'] = $mapTheme;
$etag = hash('sha256', $serverID.$now);
$map = [
+685 -653
View File
@@ -1,654 +1,686 @@
function is_touch_device() {
var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
var mq = function(query) {
return window.matchMedia(query).matches;
}
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) {
return true;
}
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
return mq(query);
}
function reloadWorldMap(option){
var $world_map = $('.world_map');
if($world_map.length == 0){
return;
}
var defaultOption = {
isDetailMap:true, //복잡 지도, 단순 지도
clickableAll:false, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도.
selectCallback:null, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행.
hrefTemplate:'#', //도시가 클릭가능할 경우 지정할 href값. {0}은 도시 id로 변환됨
useCachedMap:false, //맵 캐시를 사용
//아래부터는 post query에 들어갈 녀석
year:null, //year값, 연감등에 사용
month:null, //month값, 연감등에 사용
aux:null, //기타 넣고 싶은 값을 입력
neutralView:false, //clickable, 소속 국가, 첩보 여부 등을 반환여부를 설정
showMe:true, //반환 값에 본인이 위치한 도시 값을 반환하도록 설정. neutralView와 별개
targetJson:'j_map.php',
//기타 보조 값
startYear:null,
};
option = $.extend(defaultOption, option);
var useCachedMap = option.useCachedMap;
var isDetailMap = option.isDetailMap;
var clickableAll = option.clickableAll;
var selectCallback = option.selectCallback;
var hrefTemplate = option.hrefTemplate;
var cityPosition = getCityPosition();
var storedOldMapKey = 'sam.{0}.map'.format(serverNick);
var storedStartYear = 'sam.{0}.startYear'.format(serverNick);
//OBJ : startYear, year, month, cityList, nationList, spyList, shownByGeneralList, myCity
function checkReturnObject(obj){
if(!obj.result){
var obj = $.Deferred();
obj.reject('fail');
return obj.promise();
}
if(!$.isNumeric(obj.startYear)
||!$.isNumeric(obj.year)
||!$.isNumeric(obj.month)
){
var obj = $.Deferred();
obj.reject('fail');
return obj.promise();
}
if(useCachedMap){
localStorage.setItem(storedOldMapKey, JSON.stringify([serverID, obj]));
localStorage.setItem(storedStartYear, JSON.stringify(obj.startYear));
}
$world_map.removeClass('draw_required');
return obj;
}
function setMapBackground(obj){
var startYear = obj.startYear;
var year = obj.year;
var month = obj.month;
if(isDetailMap){
$world_map.addClass('map_detail').removeClass('map_basic');
}
else{
$world_map.addClass('map_basic').removeClass('map_detail');
}
var $map_title = $('.map_title_text');
if(year < startYear + 1){
$map_title.css('color', 'magenta');
}
else if(year < startYear + 2){
$map_title.css('color', 'orange');
}
else if(year < startYear + 3){
$map_title.css('color', 'yellow');
}
$map_title_tooltip = $('.map_title .tooltiptext');
$map_title_tooltip.empty();
var tooltipTexts = [];
if(year < startYear + 3){
var startYearText = [];
var remainYear = startYear + 3 - year;
var remainMonth = 12 - month + 1;
if(remainMonth > 0){
remainYear -= 1;
}
if(remainYear){
startYearText.push('{0}년'.format(remainYear));
}
if(remainMonth){
startYearText.push('{0}개월'.format(remainMonth));
}
tooltipTexts.push('초반제한 기간 : {0} ({1}년)'.format(startYearText.join(' '), startYear + 3));
}
var currentTechLimit = Math.floor(Math.max(0, year - startYear) / 5) + 1;
var nextTechLimitYear = currentTechLimit * 5 + startYear;
tooltipTexts.push('기술등급 제한 : {0}등급 ({1}년 해제)'.format(currentTechLimit, nextTechLimitYear, currentTechLimit+1));
$map_title_tooltip.html(tooltipTexts.join('<br>'));
$world_map.removeClass('map_string map_summer map_fall map_winter');
if(month <= 3){
$world_map.addClass('map_spring');
}
else if(month <= 6){
$world_map.addClass('map_summer');
}
else if(month <= 9){
$world_map.addClass('map_fall');
}
else{
$world_map.addClass('map_winter');
}
$map_title.html('{0}年 {1}月'.format(year, month));
return obj;
}
function convertCityObjs(obj){
//원본 Obj는 굉장히 간소하게 온다, Object 형태로 변환해서 사용한다.
function toCityObj(arr){
return {
id:arr[0],
level:arr[1],
state:arr[2],
nationId:(arr[3]>0)?arr[3]:null,
region:arr[4],
supply:(arr[5]!=0)
};
}
function toNationObj(arr){
return {
id:arr[0],
name:arr[1],
color:arr[2],
capital:arr[3]
};
}
var cityList = obj.cityList.map(toCityObj);
var nationList = obj.nationList.map(toNationObj);
nationList = convertDictById(nationList); //array of object -> dict
var spyList = obj.spyList;
var shownByGeneralList = convertSet(obj.shownByGeneralList);//Array -> Set
var myCity = obj.myCity;
var myNation = obj.myNation;
function mergePositionInfo(city){
var id = city.id;
if(!(id in cityPosition)){
return city;
}
var xy_val = cityPosition[id];
city.name = xy_val[0];
city.x = xy_val[1];
city.y = xy_val[2];
return city;
}
function mergeNationInfo(city){
//nationId 값으로 isCapital, color, nation을 통합
var nationId = city.nationId;
if(nationId === null || !(nationId in nationList)){
city.nationId = null;
city.nation = null;
city.color = null;
city.isCapital = false;
return city;
}
var nationObj = nationList[nationId];
city.nation = nationObj.name;
city.color = nationObj.color;
city.isCapital = (nationObj.capital == city.id);
return city;
}
function mergeClickable(city){
//clickable = (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll
var id = city.id;
var nationId = city.nationId;
var clickable = 0;
if(id in spyList){
clickable |= spyList[id] << 3;
}
if(myNation !== null && nationId == myNation){
clickable |= 4;
}
if(shownByGeneralList.hasOwnProperty(id)){
clickable |= 2;
}
if(myCity !== null && id == myCity){
clickable |= 2;
}
if(clickableAll){
clickable |= 1;
}
city.clickable = clickable;
return city;
}
cityList = cityList
.map(mergePositionInfo)
.map(mergeNationInfo)
.map(mergeClickable)
.map(formatCityInfo);
return {
'cityList' : cityList,
'myCity' : myCity
};
}
function drawDetailWorldMap(obj){
var $map_body = $('.world_map .map_body');
var cityList = obj.cityList;
var myCity = obj.myCity;
cityList.forEach(function(city){
var id = city.id;
$('.city_base_{0}'.format(id)).detach();
//이전 도시는 지운다.
var $cityObj = $('<div class="city_base city_base_{0}"></div>'.format(id));
$cityObj.addClass('city_level_{0}'.format(city.level));
$cityObj.data('obj', city).css({'left':city.x-20,'top':city.y-15});
if('color' in city && city.color !== null){
var $bgObj = $('<div class="city_bg"></div>');
$cityObj.append($bgObj);
$bgObj.css({'background-image':'url({0}/b{1}.png)'.format(pathConfig.gameImage, convColorValue(city.color))});
}
var $linkObj = $('<a class="city_link"></a>');
$linkObj.data({'text':city.text,'nation':city.nation,'id':city.id});
$cityObj.append($linkObj);
var $imgObj = $('<div class="city_img"><img src="{0}/cast_{1}.gif"><div class="city_filler"></div></div>'.format(pathConfig.gameImage, city.level));
$linkObj.append($imgObj);
if(city.state > 0){
var $stateObj = $('<div class="city_state"><img src="{0}/event{1}.gif"></div>'.format(pathConfig.gameImage, city.state));
$linkObj.append($stateObj);
}
if(city.nationId && city.nationId > 0){
var flagType = city.supply?'f':'d';
var $flagObj = $('<div class="city_flag"><img src="{0}/{1}{2}.gif"></div>'.format(pathConfig.gameImage, flagType, convColorValue(city.color)));
if(city.isCapital){
var $capitalObj = $('<div class="city_capital"><img src="{0}/event51.gif"></div>'.format(pathConfig.gameImage));
$flagObj.append($capitalObj);
}
$imgObj.append($flagObj);
}
var $nameObj = $('<span class="city_detail_name">{0}</span>'.format(city.name));
$imgObj.append($nameObj);
$map_body.append($cityObj);
});
$world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city');
return obj;
}
function drawBasicWorldMap(obj){
var $map_body = $('.world_map .map_body');
var cityList = obj.cityList;
var myCity = obj.myCity;
cityList.forEach(function(city){
var id = city.id;
$('.city_base_{0}'.format(id)).detach();
//이전 도시는 지운다.
var $cityObj = $('<div class="city_base city_base_{0}"></div>'.format(id));
$cityObj.addClass('city_level_{0}'.format(city.level));
$cityObj.data('obj', city).css({'left':city.x-20,'top':city.y-15});
var $linkObj = $('<a class="city_link"></a>');
$linkObj.data({'text':city.text,'nation':city.nation,'id':city.id});
$cityObj.append($linkObj);
var $imgObj = $('<div class="city_img"><div class="city_filler"></div></div>');
if('color' in city && city.color !== null){
$imgObj.css({'background-color':city.color});
}
$linkObj.append($imgObj);
if(city.state > 0){
var state_text = 'wrong';
if(city.state < 10){
state_text = 'good';
}
else if(city.state < 40){
state_text = 'bad';
}
else if(city.state < 50){
state_text = 'war';
}
var $stateObj = $('<div class="city_state city_state_{0}"></div>'.format(state_text));
$imgObj.append($stateObj);
}
//단순 표기에서는 깃발 여부가 없음
if(city.isCapital){
var $capitalObj = $('<div class="city_capital"></div>');
$imgObj.append($capitalObj);
}
var $nameObj = $('<span class="city_detail_name">{0}</span>'.format(city.name));
$imgObj.append($nameObj);
$map_body.append($cityObj);
});
$world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city');
return obj;
}
function setMouseWork(obj){
var $tooltip = $('.world_map .city_tooltip');
var $tooltip_city = $tooltip.find('.city_name');
var $tooltip_nation = $tooltip.find('.nation_name');
var $objs = $('.world_map .city_link');
var $map_body = $('.world_map .map_body');
//터치스크린 탭
if(!option.neutralView && is_touch_device()){
$objs.on('touchstart', function(e){
if(window.sam_toggleSingleTap){
return true;
}
var $this = $(this);
var touchMode = $this.data('touchMode');
if($tooltip_city.data('target') != $this.data('id')){
$this.data('touchMode', 1);
}
else if(touchMode === undefined){
$this.data('touchMode', 1);
}
else{
$this.data('touchMode', touchMode + 1);
}
$map_body.data('touchMode', 1);
$tooltip_city.data('target', $this.data('id'));
});
$objs.on('touchend', function(e){
if(window.sam_toggleSingleTap){
return true;
}
var $this = $(this);
var position = $this.parent().position();
$tooltip_city.html($this.data('text'));
var nation_text = $this.data('nation');
if(nation_text){
$tooltip_nation.html(nation_text).show();
}
else{
$tooltip_nation.html('').hide();
}
$tooltip.css({'top': position.top + 25, 'left': position.left + 35}).show();
var touchMode = $this.data('touchMode');
if(touchMode <= 1){
return false;
}
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
$this.data('touchMode', 0);
});
$map_body.on('touchend',function(e){
if(window.sam_toggleSingleTap){
return true;
}
//위의 touchend bind에 해당하지 않는 경우 -> 빈 지도 터치
$tooltip.hide();
});
}
//Mouse over 모드 작동
$map_body.on('mousemove', function(e){
if($(this).data('touchMode')){
return true;
}
var parentOffset = $map_body.offset();
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
$tooltip.css({'top': relY + 10, 'left': relX + 10});
});
$objs.on('mouseenter', function(e){
if($map_body.data('touchMode')){
return true;
}
var $this = $(this);
$tooltip_city.data('target', $this.data('id'));
$tooltip_city.html($this.data('text'));
var nation_text = $this.data('nation');
if(nation_text){
$tooltip_nation.html(nation_text).show();
}
else{
$tooltip_nation.html('').hide();
}
$tooltip.show();
});
$objs.on('mouseleave', function(event){
$tooltip.hide();
});
$objs.on('click', function(e){
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
var touchMode = $(this).data('touchMode');
if(touchMode === undefined){
return;
}
if(touchMode === 1){
return false;
}
});
return obj;
}
function setCityClickable(obj){
obj.cityList.forEach(function(city){
var $cityLink = $world_map.find('.city_base_{0} .city_link'.format(city.id));
if('clickable' in city && city.clickable > 0){
$cityLink.attr('href',hrefTemplate.format(city.id));
}
if(selectCallback){
$cityLink.click(function(){
return selectCallback(city);
});
}
});
return obj;
}
function saveCityInfo(obj){
$world_map.data('cityInfo', obj);
return obj;
}
var $hideCityNameBtn = $world_map.find('.map_toggle_cityname');
if(localStorage.getItem('sam.hideMapCityName') == 'yes'){
$world_map.addClass('hide_cityname');
$hideCityNameBtn.addClass('active').attr('aria-pressed', 'true');
}
$hideCityNameBtn.click(function(){
//이전 상태 확인
var state = !$hideCityNameBtn.hasClass('active');
if(state){
$world_map.addClass('hide_cityname');
localStorage.setItem('sam.hideMapCityName', 'yes');
}
else{
$world_map.removeClass('hide_cityname');
localStorage.setItem('sam.hideMapCityName', 'no');
}
});
var $toggleSingleTapBtn = $world_map.find('.map_toggle_single_tap');
if(localStorage.getItem('sam.toggleSingleTap') == 'yes'){
window.sam_toggleSingleTap = true;
$toggleSingleTapBtn.addClass('active').attr('aria-pressed', 'true');
}
else{
window.sam_toggleSingleTap = false;
}
var $map_body = $('.world_map .map_body');
$toggleSingleTapBtn.click(function(){
//이전 상태 확인
var state = !$toggleSingleTapBtn.hasClass('active');
if(state){
$map_body.removeData('touchMode');
localStorage.setItem('sam.toggleSingleTap', 'yes');
window.sam_toggleSingleTap = true;
}
else{
localStorage.setItem('sam.toggleSingleTap', 'no');
window.sam_toggleSingleTap = false;
}
});
if(isDetailMap){
$world_map.addClass('map_detail');
}
else{
$world_map.removeClass('map_datail');
}
//deferred mode of jQuery. != promise-then.
var deferred = $.ajax({
url: option.targetJson,
type: 'post',
dataType:'json',
data: {
data: JSON.stringify({
neutralView:option.neutralView,
year:option.year,
month:option.month,
showMe:option.showMe,
aux:option.aux
})
}
});
deferred
.then(checkReturnObject)
.then(setMapBackground)
.then(convertCityObjs)
.then(isDetailMap?drawDetailWorldMap:drawBasicWorldMap)
.then(setMouseWork)
.then(setCityClickable)
.then(saveCityInfo);
if($world_map.hasClass('draw_required')){
if(useCachedMap){
//일단 불러옴
do{
var storedMap = localStorage.getItem(storedOldMapKey);
if(!storedMap){
break;
}
storedMap = JSON.parse(storedMap);
var storedServerID = storedMap[0];
if(storedServerID != serverID){
break;
}
storedMap = storedMap[1];
storedMap = setMapBackground(storedMap);
storedMap = convertCityObjs(storedMap);
if(isDetailMap){
storedMap = drawDetailWorldMap(storedMap);
}
else{
storedMap = drawBasicWorldMap(storedMap);
}
storedMap = setMouseWork(storedMap);
storedMap = setCityClickable(storedMap);
storedMap = saveCityInfo(storedMap);
}while(false);
}
else if(option.year && option.month){
var startYear = localStorage.getItem(storedStartYear);
if(startYear){
startYear = JSON.parse(startYear);
}
else{
startYear = option.year;
}
var tmp = {
year : option.year,
month : option.month,
startYear : startYear
};
setMapBackground(tmp);
}
}
}
$(function(){
if(is_touch_device()){
$('.map_body .map_toggle_single_tap').show();
}
function is_touch_device() {
var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
var mq = function(query) {
return window.matchMedia(query).matches;
}
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) {
return true;
}
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
return mq(query);
}
function reloadWorldMap(option, drawTarget) {
if (drawTarget === undefined || drawTarget === null) {
drawTarget = '.world_map'
}
var $world_map = $(drawTarget);
if ($world_map.length == 0) {
return;
}
var defaultOption = {
isDetailMap: true, //복잡 지도, 단순 지도
clickableAll: false, //어떤 경우든 클릭을 가능하게 함. 해당 동작의 동작 가능성 여부와는 별도.
selectCallback: null, //callback을 지정시 clickable과 관계 없이 해당 함수를 실행.
hrefTemplate: '#', //도시가 클릭가능할 경우 지정할 href값. {0}은 도시 id로 변환됨
useCachedMap: false, //맵 캐시를 사용
//아래부터는 post query에 들어갈 녀석
year: null, //year값, 연감등에 사용
month: null, //month값, 연감등에 사용
aux: null, //기타 넣고 싶은 값을 입력
neutralView: false, //clickable, 소속 국가, 첩보 여부 등을 반환여부를 설정
showMe: true, //반환 값에 본인이 위치한 도시 값을 반환하도록 설정. neutralView와 별개
targetJson: 'j_map.php',
reqType: 'post',
dynamicMapTheme: false,
callback: null,
//기타 보조 값
startYear: null,
};
option = $.extend(defaultOption, option);
var useCachedMap = option.useCachedMap;
var isDetailMap = option.isDetailMap;
var clickableAll = option.clickableAll;
var selectCallback = option.selectCallback;
var hrefTemplate = option.hrefTemplate;
var cityPosition = getCityPosition();
var storedOldMapKey = 'sam.{0}.map'.format(serverNick);
var storedStartYear = 'sam.{0}.startYear'.format(serverNick);
//OBJ : startYear, year, month, cityList, nationList, spyList, shownByGeneralList, myCity
function checkReturnObject(obj) {
if (!obj.result) {
var obj = $.Deferred();
obj.reject('fail');
return obj.promise();
}
if (!$.isNumeric(obj.startYear) ||
!$.isNumeric(obj.year) ||
!$.isNumeric(obj.month)
) {
var obj = $.Deferred();
obj.reject('fail');
return obj.promise();
}
if (useCachedMap) {
localStorage.setItem(storedOldMapKey, JSON.stringify([serverID, obj]));
localStorage.setItem(storedStartYear, JSON.stringify(obj.startYear));
}
$world_map.removeClass('draw_required');
return obj;
}
function setMapBackground(obj) {
function setTheme() {
var oldTheme = $world_map.data('currentTheme');
var newTheme = obj.theme;
if (oldTheme === newTheme) {
return;
}
if (oldTheme) {
$world_map.removeClass('map_theme_' + oldTheme);
}
$world_map.addClass('map_theme_' + newTheme);
$world_map.data('currentTheme', newTheme);
}
if (option.dynamicMapTheme) {
setTheme();
}
var startYear = obj.startYear;
var year = obj.year;
var month = obj.month;
if (isDetailMap) {
$world_map.addClass('map_detail').removeClass('map_basic');
} else {
$world_map.addClass('map_basic').removeClass('map_detail');
}
var $map_title = $('.map_title_text');
if (year < startYear + 1) {
$map_title.css('color', 'magenta');
} else if (year < startYear + 2) {
$map_title.css('color', 'orange');
} else if (year < startYear + 3) {
$map_title.css('color', 'yellow');
}
$map_title_tooltip = $('.map_title .tooltiptext');
$map_title_tooltip.empty();
var tooltipTexts = [];
if (year < startYear + 3) {
var startYearText = [];
var remainYear = startYear + 3 - year;
var remainMonth = 12 - month + 1;
if (remainMonth > 0) {
remainYear -= 1;
}
if (remainYear) {
startYearText.push('{0}년'.format(remainYear));
}
if (remainMonth) {
startYearText.push('{0}개월'.format(remainMonth));
}
tooltipTexts.push('초반제한 기간 : {0} ({1}년)'.format(startYearText.join(' '), startYear + 3));
}
var currentTechLimit = Math.floor(Math.max(0, year - startYear) / 5) + 1;
var nextTechLimitYear = currentTechLimit * 5 + startYear;
tooltipTexts.push('기술등급 제한 : {0}등급 ({1}년 해제)'.format(currentTechLimit, nextTechLimitYear, currentTechLimit + 1));
$map_title_tooltip.html(tooltipTexts.join('<br>'));
$world_map.removeClass('map_string map_summer map_fall map_winter');
if (month <= 3) {
$world_map.addClass('map_spring');
} else if (month <= 6) {
$world_map.addClass('map_summer');
} else if (month <= 9) {
$world_map.addClass('map_fall');
} else {
$world_map.addClass('map_winter');
}
$map_title.html('{0}年 {1}月'.format(year, month));
return obj;
}
function convertCityObjs(obj) {
//원본 Obj는 굉장히 간소하게 온다, Object 형태로 변환해서 사용한다.
function toCityObj(arr) {
return {
id: arr[0],
level: arr[1],
state: arr[2],
nationId: (arr[3] > 0) ? arr[3] : null,
region: arr[4],
supply: (arr[5] != 0)
};
}
function toNationObj(arr) {
return {
id: arr[0],
name: arr[1],
color: arr[2],
capital: arr[3]
};
}
var cityList = obj.cityList.map(toCityObj);
var nationList = obj.nationList.map(toNationObj);
nationList = convertDictById(nationList); //array of object -> dict
var spyList = obj.spyList;
var shownByGeneralList = convertSet(obj.shownByGeneralList); //Array -> Set
var myCity = obj.myCity;
var myNation = obj.myNation;
function mergePositionInfo(city) {
var id = city.id;
if (!(id in cityPosition)) {
return city;
}
var xy_val = cityPosition[id];
city.name = xy_val[0];
city.x = xy_val[1];
city.y = xy_val[2];
return city;
}
function mergeNationInfo(city) {
//nationId 값으로 isCapital, color, nation을 통합
var nationId = city.nationId;
if (nationId === null || !(nationId in nationList)) {
city.nationId = null;
city.nation = null;
city.color = null;
city.isCapital = false;
return city;
}
var nationObj = nationList[nationId];
city.nation = nationObj.name;
city.color = nationObj.color;
city.isCapital = (nationObj.capital == city.id);
return city;
}
function mergeClickable(city) {
//clickable = (remainSpy << 3) | (ourCity << 2) | (shownByGeneral << 1) | clickableAll
var id = city.id;
var nationId = city.nationId;
var clickable = 0;
if (id in spyList) {
clickable |= spyList[id] << 3;
}
if (myNation !== null && nationId == myNation) {
clickable |= 4;
}
if (shownByGeneralList.hasOwnProperty(id)) {
clickable |= 2;
}
if (myCity !== null && id == myCity) {
clickable |= 2;
}
if (clickableAll) {
clickable |= 1;
}
city.clickable = clickable;
return city;
}
cityList = cityList
.map(mergePositionInfo)
.map(mergeNationInfo)
.map(mergeClickable)
.map(formatCityInfo);
return {
'cityList': cityList,
'myCity': myCity
};
}
function drawDetailWorldMap(obj) {
var $map_body = $(drawTarget + ' .map_body');
var cityList = obj.cityList;
var myCity = obj.myCity;
cityList.forEach(function(city) {
var id = city.id;
$('.city_base_{0}'.format(id)).detach();
//이전 도시는 지운다.
var $cityObj = $('<div class="city_base city_base_{0}"></div>'.format(id));
$cityObj.addClass('city_level_{0}'.format(city.level));
$cityObj.data('obj', city).css({ 'left': city.x - 20, 'top': city.y - 15 });
if ('color' in city && city.color !== null) {
var $bgObj = $('<div class="city_bg"></div>');
$cityObj.append($bgObj);
$bgObj.css({ 'background-image': 'url({0}/b{1}.png)'.format(pathConfig.gameImage, convColorValue(city.color)) });
}
var $linkObj = $('<a class="city_link"></a>');
$linkObj.data({ 'text': city.text, 'nation': city.nation, 'id': city.id });
$cityObj.append($linkObj);
var $imgObj = $('<div class="city_img"><img src="{0}/cast_{1}.gif"><div class="city_filler"></div></div>'.format(pathConfig.gameImage, city.level));
$linkObj.append($imgObj);
if (city.state > 0) {
var $stateObj = $('<div class="city_state"><img src="{0}/event{1}.gif"></div>'.format(pathConfig.gameImage, city.state));
$linkObj.append($stateObj);
}
if (city.nationId && city.nationId > 0) {
var flagType = city.supply ? 'f' : 'd';
var $flagObj = $('<div class="city_flag"><img src="{0}/{1}{2}.gif"></div>'.format(pathConfig.gameImage, flagType, convColorValue(city.color)));
if (city.isCapital) {
var $capitalObj = $('<div class="city_capital"><img src="{0}/event51.gif"></div>'.format(pathConfig.gameImage));
$flagObj.append($capitalObj);
}
$imgObj.append($flagObj);
}
var $nameObj = $('<span class="city_detail_name">{0}</span>'.format(city.name));
$imgObj.append($nameObj);
$map_body.append($cityObj);
});
$world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city');
return obj;
}
function drawBasicWorldMap(obj) {
var $map_body = $(drawTarget + ' .map_body');
var cityList = obj.cityList;
var myCity = obj.myCity;
cityList.forEach(function(city) {
var id = city.id;
$('.city_base_{0}'.format(id)).detach();
//이전 도시는 지운다.
var $cityObj = $('<div class="city_base city_base_{0}"></div>'.format(id));
$cityObj.addClass('city_level_{0}'.format(city.level));
$cityObj.data('obj', city).css({ 'left': city.x - 20, 'top': city.y - 15 });
var $linkObj = $('<a class="city_link"></a>');
$linkObj.data({ 'text': city.text, 'nation': city.nation, 'id': city.id });
$cityObj.append($linkObj);
var $imgObj = $('<div class="city_img"><div class="city_filler"></div></div>');
if ('color' in city && city.color !== null) {
$imgObj.css({ 'background-color': city.color });
}
$linkObj.append($imgObj);
if (city.state > 0) {
var state_text = 'wrong';
if (city.state < 10) {
state_text = 'good';
} else if (city.state < 40) {
state_text = 'bad';
} else if (city.state < 50) {
state_text = 'war';
}
var $stateObj = $('<div class="city_state city_state_{0}"></div>'.format(state_text));
$imgObj.append($stateObj);
}
//단순 표기에서는 깃발 여부가 없음
if (city.isCapital) {
var $capitalObj = $('<div class="city_capital"></div>');
$imgObj.append($capitalObj);
}
var $nameObj = $('<span class="city_detail_name">{0}</span>'.format(city.name));
$imgObj.append($nameObj);
$map_body.append($cityObj);
});
$world_map.find('.city_base_{0} .city_filler'.format(myCity)).addClass('my_city');
return obj;
}
function setMouseWork(obj) {
var $tooltip = $(drawTarget + ' .city_tooltip');
var $tooltip_city = $tooltip.find('.city_name');
var $tooltip_nation = $tooltip.find('.nation_name');
var $objs = $(drawTarget + ' .city_link');
var $map_body = $(drawTarget + ' .map_body');
//터치스크린 탭
if (!option.neutralView && is_touch_device()) {
$objs.on('touchstart', function(e) {
if (window.sam_toggleSingleTap) {
return true;
}
var $this = $(this);
var touchMode = $this.data('touchMode');
if ($tooltip_city.data('target') != $this.data('id')) {
$this.data('touchMode', 1);
} else if (touchMode === undefined) {
$this.data('touchMode', 1);
} else {
$this.data('touchMode', touchMode + 1);
}
$map_body.data('touchMode', 1);
$tooltip_city.data('target', $this.data('id'));
});
$objs.on('touchend', function(e) {
if (window.sam_toggleSingleTap) {
return true;
}
var $this = $(this);
var position = $this.parent().position();
$tooltip_city.html($this.data('text'));
var nation_text = $this.data('nation');
if (nation_text) {
$tooltip_nation.html(nation_text).show();
} else {
$tooltip_nation.html('').hide();
}
var left = position.left;
var top = position.top;
var scale = $map_body.data('scale');
if (scale) {
left /= scale;
top /= scale;
}
$tooltip.css({ 'top': top + 25, 'left': left + 35 }).show();
var touchMode = $this.data('touchMode');
if (touchMode <= 1) {
return false;
}
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
$this.data('touchMode', 0);
});
$map_body.on('touchend', function(e) {
if (window.sam_toggleSingleTap) {
return true;
}
//위의 touchend bind에 해당하지 않는 경우 -> 빈 지도 터치
$tooltip.hide();
});
}
//Mouse over 모드 작동
$map_body.on('mousemove', function(e) {
if ($(this).data('touchMode')) {
return true;
}
var rect = this.getBoundingClientRect();
var left = (e.clientX - rect.left - this.clientLeft + this.scrollLeft);
var top = (e.clientY - rect.top - this.clientTop + this.scrollTop);
var scale = $map_body.data('scale');
if (scale) {
left /= scale;
top /= scale;
}
$tooltip.css({ 'top': top + 10, 'left': left + 10 });
});
$objs.on('mouseenter', function(e) {
if ($map_body.data('touchMode')) {
return true;
}
var $this = $(this);
$tooltip_city.data('target', $this.data('id'));
$tooltip_city.html($this.data('text'));
var nation_text = $this.data('nation');
if (nation_text) {
$tooltip_nation.html(nation_text).show();
} else {
$tooltip_nation.html('').hide();
}
$tooltip.show();
});
$objs.on('mouseleave', function(event) {
$tooltip.hide();
});
$objs.on('click', function(e) {
//xxx: touchend 다음 click 이벤트가 갈 수도 있고, 안 갈 수도 있다.
var touchMode = $(this).data('touchMode');
if (touchMode === undefined) {
return;
}
if (touchMode === 1) {
return false;
}
});
return obj;
}
function setCityClickable(obj) {
obj.cityList.forEach(function(city) {
var $cityLink = $world_map.find('.city_base_{0} .city_link'.format(city.id));
if ('clickable' in city && city.clickable > 0) {
$cityLink.attr('href', hrefTemplate.format(city.id));
}
if (selectCallback) {
$cityLink.click(function() {
return selectCallback(city);
});
}
});
return obj;
}
function saveCityInfo(obj) {
$world_map.data('cityInfo', obj);
return obj;
}
var $hideCityNameBtn = $world_map.find('.map_toggle_cityname');
if (localStorage.getItem('sam.hideMapCityName') == 'yes') {
$world_map.addClass('hide_cityname');
$hideCityNameBtn.addClass('active').attr('aria-pressed', 'true');
}
$hideCityNameBtn.click(function() {
//이전 상태 확인
var state = !$hideCityNameBtn.hasClass('active');
if (state) {
$world_map.addClass('hide_cityname');
localStorage.setItem('sam.hideMapCityName', 'yes');
} else {
$world_map.removeClass('hide_cityname');
localStorage.setItem('sam.hideMapCityName', 'no');
}
});
var $toggleSingleTapBtn = $world_map.find('.map_toggle_single_tap');
if (localStorage.getItem('sam.toggleSingleTap') == 'yes') {
window.sam_toggleSingleTap = true;
$toggleSingleTapBtn.addClass('active').attr('aria-pressed', 'true');
} else {
window.sam_toggleSingleTap = false;
}
var $map_body = $(drawTarget + ' .map_body');
$toggleSingleTapBtn.click(function() {
//이전 상태 확인
var state = !$toggleSingleTapBtn.hasClass('active');
if (state) {
$map_body.removeData('touchMode');
localStorage.setItem('sam.toggleSingleTap', 'yes');
window.sam_toggleSingleTap = true;
} else {
localStorage.setItem('sam.toggleSingleTap', 'no');
window.sam_toggleSingleTap = false;
}
});
if (isDetailMap) {
$world_map.addClass('map_detail');
} else {
$world_map.removeClass('map_datail');
}
//deferred mode of jQuery. != promise-then.
var deferred = $.ajax({
url: option.targetJson,
type: option.reqType,
dataType: 'json',
ifModified: true,
data: {
data: JSON.stringify({
neutralView: option.neutralView,
year: option.year,
month: option.month,
showMe: option.showMe,
aux: option.aux
})
}
});
var rawObject = null;
deferred
.then(function(data) {
rawObject = data;
return data;
})
.then(checkReturnObject)
.then(setMapBackground)
.then(convertCityObjs)
.then(isDetailMap ? drawDetailWorldMap : drawBasicWorldMap)
.then(setMouseWork)
.then(setCityClickable)
.then(saveCityInfo)
.then(function(data) {
if (option.callback) {
option.callback(data, rawObject);
}
});
if ($world_map.hasClass('draw_required')) {
if (useCachedMap) {
//일단 불러옴
do {
var storedMap = localStorage.getItem(storedOldMapKey);
if (!storedMap) {
break;
}
storedMap = JSON.parse(storedMap);
var storedServerID = storedMap[0];
if (storedServerID != serverID) {
break;
}
storedMap = storedMap[1];
storedMap = setMapBackground(storedMap);
storedMap = convertCityObjs(storedMap);
if (isDetailMap) {
storedMap = drawDetailWorldMap(storedMap);
} else {
storedMap = drawBasicWorldMap(storedMap);
}
storedMap = setMouseWork(storedMap);
storedMap = setCityClickable(storedMap);
storedMap = saveCityInfo(storedMap);
} while (false);
} else if (option.year && option.month) {
var startYear = localStorage.getItem(storedStartYear);
if (startYear) {
startYear = JSON.parse(startYear);
} else {
startYear = option.year;
}
var tmp = {
year: option.year,
month: option.month,
startYear: startYear
};
setMapBackground(tmp);
}
}
}
$(function() {
if (is_touch_device()) {
$('.map_body .map_toggle_single_tap').show();
}
})
+280 -231
View File
@@ -1,232 +1,281 @@
<?php
namespace sammo;
require(__DIR__ . '/vendor/autoload.php');
if (!class_exists('\\sammo\\RootDB')) {
header('Location:install.php');
die();
}
$session = Session::getInstance();
use \kakao\KakaoKey as KakaoKey;
if ($session->isLoggedIn()) {
header('Location:i_entrance/entrance.php');
die();
}
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>삼국지 모의전투 HiDCHe</title>
<?= WebUtil::printJS('e_lib/jquery-3.3.1.min.js') ?>
<?= WebUtil::printJS('e_lib/bootstrap.bundle.min.js') ?>
<?= WebUtil::printJS('e_lib/jquery.validate.min.js') ?>
<?= WebUtil::printJS('e_lib/sha512.min.js') ?>
<?= WebUtil::printJS('js/common.js') ?>
<?= WebUtil::printJS('js/login.js') ?>
<?= WebUtil::printCSS('e_lib/bootstrap.min.css') ?>
<?= WebUtil::printCSS('css/login.css') ?>
<meta name="description" content="실시간으로 진행되는 삼국지 웹게임(삼모전)입니다">
<meta name="keywords" content="삼국지,삼모전,웹게임,힏체,힏체섭,히데체,히데체섭,HiDCHe,체섭">
<meta property="og:type" content="website">
<meta property="og:title" content="삼국지 모의전투 HiDCHe">
<meta property="og:description" content="실시간으로 진행되는 삼국지 웹게임(삼모전)입니다">
<meta property="og:url" content="https://sam.hided.net">
<script>
var oauthMode = null;
function getOAuthToken(mode, scope_list) {
if (mode === undefined) {
mode = 'login';
}
if (scope_list === undefined) {
scope_list = null;
}
oauthMode = mode;
var url = 'https://kauth.kakao.com/oauth/authorize?' +
'client_id=<?= KakaoKey::REST_KEY ?>&' +
'redirect_uri=<?= KakaoKey::REDIRECT_URI ?>&' +
'response_type=code';
if (Array.isArray(scope_list)) {
url += '&scope=' + scope_list.join(',');
} else if (typeof scope_list === 'string' || scope_list instanceof String) {
url += '&scope=' + scope_list;
}
window.open(url, "KakaoAccountLogin", "width=600,height=450,resizable=yes,scrollbars=yes");
}
function sendTempPasswordToKakaoTalk() {
$.post({
url: 'oauth_kakao/j_login_oauth.php',
dataType: 'json'
}).then(function(obj) {
var t = $.Deferred();
if (!obj.result) {
t.reject();
}
return $.post({
url: 'oauth_kakao/j_change_pw.php',
dataType: 'json'
});
}).then(function(obj) {
if (!obj.result) {
alert(obj.reason);
} else {
alert('임시 비밀번호가 카카오톡으로 전송되었습니다.');
}
});
}
function doLoginUsingOAuth() {
$.post({
url: 'oauth_kakao/j_login_oauth.php',
dataType: 'json'
}).then(function(obj) {
if (obj.result) {
window.location.href = "./";
return;
}
if (!obj.reqOTP) {
alert(obj.reason);
return;
}
$('#modalOTP').modal().on('shown.bs.modal', function() {
$('#otp_code').focus();
});
});
}
function postOAuthResult(result) {
if (result == 'join') {
window.location.href = 'oauth_kakao/join.php';
} else if (result == 'req_email') {
alert('이메일 정보 공유를 허가해 주셔야 합니다.');
} else if (result == 'login') {
console.log('로그인모드');
if (oauthMode == 'change_pw') {
sendTempPasswordToKakaoTalk();
} else {
doLoginUsingOAuth();
}
} else {
alert('예외 발생!');
}
}
</script>
</head>
<body>
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark">
<a class="navbar-brand" href=".">삼국지 모의전투 HiDCHe</a>
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<?= WebUtil::drawMenu(ROOT . '/d_shared/menu.json') ?>
</ul>
</div>
</nav>
<div class="full-content">
<div class="vertical-center">
<div class="container">
<h1 class="row justify-content-md-center">삼국지 모의전투 HiDCHe</h1>
<div class="row justify-content-md-center">
<div class="col" style="max-width:450px;">
<div class="card" id="login_card">
<h3 class="card-header">
로그인
</h3>
<div class="card-body">
<form id="main_form" method="post" action="#">
<div class="form-group row">
<label for="username" class="col-5 col-md-4 col-form-label">계정명</label>
<div class="col-7 col-md-8">
<input autocomplete="username" type="text" class="form-control" name="username" id="username" autofocus="autofocus" placeholder="계정명" />
</div>
</div>
<div class="form-group row">
<label for="password" class="col-5 col-md-4 col-form-label">비밀번호</label>
<div class="col-7 col-md-8">
<input autocomplete="current-password" type="password" class="form-control" name="password" id="password" placeholder="비밀번호" />
</div>
</div>
<input type="hidden" id="global_salt" name="global_salt" value="<?= RootDB::getGlobalSalt() ?>">
<div class="form-group row">
<div class="col-5 col-md-4 " style="position:relative;"><button type="button" onclick="getOAuthToken('login', ['account_email','talk_message']);" id="btn_kakao_login" title="카카오톡으로 가입&amp;로그인"></button></div>
<div class="col-7 col-md-8">
<div class="btn-group btn-group-lg d-flex login_btn_group" role="group">
<button type="submit" class="btn btn-primary login-button w-100">로그인</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> </button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1">
<a class="dropdown-item" href="javascript:getOAuthToken('change_pw', 'talk_message');">비밀번호 초기화</a>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="bottom_box">
<div class="container"><a href="terms.2.html">개인정보처리방침</a> &amp; <a href="terms.1.html">이용약관</a><br>© 2020 • HideD
<br>크롬과 파이어폭스에 최적화되어있습니다.</div>
</div>
</div>
<div class="modal fade" id="modalOTP" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form id="otp_form" method="post" action="#">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">인증 코드 필요</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div>
인증 코드가 필요합니다.<br><br>
카카오톡의 '나와의 채팅'란을 확인해 주세요.<br>
(별도의 알림[소리, 진동, 숫자]이 발생하지 않습니다.)
</div>
<div class="input-group mt-4" role="group">
<div class="input-group-prepend">
<span class="input-group-text">인증 코드</span>
</div>
<input type="number" class="form-control" name='otp' id="otp_code" placeholder="인증 코드">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">취소</button>
<button type="submit" class="btn btn-primary">제출</button>
</div>
</form>
</div>
</div>
</div>
</body>
<?php
namespace sammo;
require(__DIR__ . '/vendor/autoload.php');
if (!class_exists('\\sammo\\RootDB')) {
header('Location:install.php');
die();
}
$session = Session::getInstance();
use \kakao\KakaoKey as KakaoKey;
if ($session->isLoggedIn()) {
header('Location:i_entrance/entrance.php');
die();
}
$runningServer = null;
foreach(ServConfig::getServerList() as $setting){
if(!$setting->isExists()){
continue;
}
if(!$setting->isRunning()){
continue;
}
$runningServer = [
'color'=>$setting->getColor(),
'korName'=>$setting->getKorName(),
'name'=>$setting->getShortName(),
'exists'=>$setting->isExists(),
'enable'=>$setting->isRunning()
];
}
if($runningServer){
$subTemplates = new \League\Plates\Engine(__DIR__.'/'.$runningServer['name'].'/templates');
}
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>삼국지 모의전투 HiDCHe</title>
<script>
var runningServer = <?=Json::encode($runningServer)?>;
</script>
<?= WebUtil::printJS('e_lib/jquery-3.3.1.min.js') ?>
<?= WebUtil::printJS('e_lib/bootstrap.bundle.min.js') ?>
<?= WebUtil::printJS('e_lib/jquery.validate.min.js') ?>
<?= WebUtil::printJS('e_lib/sha512.min.js') ?>
<?= WebUtil::printJS('js/common.js') ?>
<?= WebUtil::printJS('js/login.js') ?>
<?= WebUtil::printJS('d_shared/common_path.js') ?>
<?= WebUtil::printCSS('d_shared/common.css') ?>
<?= WebUtil::printCSS('e_lib/bootstrap.min.css') ?>
<?= WebUtil::printCSS('css/login.css') ?>
<?php if($runningServer): ?>
<script>
var serverNick = '<?=$runningServer['korName']?>';
</script>
<?= WebUtil::printJS($runningServer['name'].'/d_shared/base_map.js') ?>
<?= WebUtil::printJS($runningServer['name'].'/js/map.js') ?>
<?= WebUtil::printCSS($runningServer['name'].'/css/map.css') ?>
<?php endif; ?>
<meta name="description" content="실시간으로 진행되는 삼국지 웹게임(삼모전)입니다">
<meta name="keywords" content="삼국지,삼모전,웹게임,힏체,힏체섭,히데체,히데체섭,HiDCHe,체섭">
<meta property="og:type" content="website">
<meta property="og:title" content="삼국지 모의전투 HiDCHe">
<meta property="og:description" content="실시간으로 진행되는 삼국지 웹게임(삼모전)입니다">
<meta property="og:url" content="https://sam.hided.net">
<script>
var oauthMode = null;
function getOAuthToken(mode, scope_list) {
if (mode === undefined) {
mode = 'login';
}
if (scope_list === undefined) {
scope_list = null;
}
oauthMode = mode;
var url = 'https://kauth.kakao.com/oauth/authorize?' +
'client_id=<?= KakaoKey::REST_KEY ?>&' +
'redirect_uri=<?= KakaoKey::REDIRECT_URI ?>&' +
'response_type=code';
if (Array.isArray(scope_list)) {
url += '&scope=' + scope_list.join(',');
} else if (typeof scope_list === 'string' || scope_list instanceof String) {
url += '&scope=' + scope_list;
}
window.open(url, "KakaoAccountLogin", "width=600,height=450,resizable=yes,scrollbars=yes");
}
function sendTempPasswordToKakaoTalk() {
$.post({
url: 'oauth_kakao/j_login_oauth.php',
dataType: 'json'
}).then(function(obj) {
var t = $.Deferred();
if (!obj.result) {
t.reject();
}
return $.post({
url: 'oauth_kakao/j_change_pw.php',
dataType: 'json'
});
}).then(function(obj) {
if (!obj.result) {
alert(obj.reason);
} else {
alert('임시 비밀번호가 카카오톡으로 전송되었습니다.');
}
});
}
function doLoginUsingOAuth() {
$.post({
url: 'oauth_kakao/j_login_oauth.php',
dataType: 'json'
}).then(function(obj) {
if (obj.result) {
window.location.href = "./";
return;
}
if (!obj.reqOTP) {
alert(obj.reason);
return;
}
$('#modalOTP').modal().on('shown.bs.modal', function() {
$('#otp_code').focus();
});
});
}
function postOAuthResult(result) {
if (result == 'join') {
window.location.href = 'oauth_kakao/join.php';
} else if (result == 'req_email') {
alert('이메일 정보 공유를 허가해 주셔야 합니다.');
} else if (result == 'login') {
console.log('로그인모드');
if (oauthMode == 'change_pw') {
sendTempPasswordToKakaoTalk();
} else {
doLoginUsingOAuth();
}
} else {
alert('예외 발생!');
}
}
</script>
</head>
<body>
<nav class="navbar navbar-expand-lg fixed-top navbar-dark bg-dark">
<a class="navbar-brand" href=".">삼국지 모의전투 HiDCHe</a>
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<?= WebUtil::drawMenu(ROOT . '/d_shared/menu.json') ?>
</ul>
</div>
</nav>
<div class="container" style="margin-top:120px;">
<h1 class="row justify-content-md-center">삼국지 모의전투 HiDCHe</h1>
<div class="row justify-content-md-center">
<div class="col" style="max-width:450px;">
<div class="card" id="login_card">
<h3 class="card-header">
로그인
</h3>
<div class="card-body">
<form id="main_form" method="post" action="#">
<div class="form-group row">
<label for="username" class="col-5 col-md-4 col-form-label">계정명</label>
<div class="col-7 col-md-8">
<input autocomplete="username" type="text" class="form-control" name="username" id="username" autofocus="autofocus" placeholder="계정명" />
</div>
</div>
<div class="form-group row">
<label for="password" class="col-5 col-md-4 col-form-label">비밀번호</label>
<div class="col-7 col-md-8">
<input autocomplete="current-password" type="password" class="form-control" name="password" id="password" placeholder="비밀번호" />
</div>
</div>
<input type="hidden" id="global_salt" name="global_salt" value="<?= RootDB::getGlobalSalt() ?>">
<div class="form-group row">
<div class="col-5 col-md-4 " style="position:relative;"><button type="button" onclick="getOAuthToken('login', ['account_email','talk_message']);" id="btn_kakao_login" title="카카오톡으로 가입&amp;로그인"></button></div>
<div class="col-7 col-md-8">
<div class="btn-group btn-group-lg d-flex login_btn_group" role="group">
<button type="submit" class="btn btn-primary login-button w-100">로그인</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> </button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1">
<a class="dropdown-item" href="javascript:getOAuthToken('change_pw', 'talk_message');">비밀번호 초기화</a>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<?php if($runningServer): ?>
<div class="row justify-content-md-center" id="running_map">
<div class="col" style="max-width:700px;">
<div class="card" style="width:700px;">
<h3 class="card-header">
<?=$runningServer['korName']?> 현황
</h3>
<div class='map-container' style='position:relative;'>
<?=$subTemplates->render('map', [
'mapTheme' => ''
])?>
</div>
<div class="card-body">
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
<div id="bottom_box">
<div class="container"><a href="terms.2.html">개인정보처리방침</a> &amp; <a href="terms.1.html">이용약관</a><br>© 2020 • HideD
<br>크롬과 파이어폭스에 최적화되어있습니다.</div>
</div>
<div class="modal fade" id="modalOTP" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form id="otp_form" method="post" action="#">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">인증 코드 필요</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div>
인증 코드가 필요합니다.<br><br>
카카오톡의 '나와의 채팅'란을 확인해 주세요.<br>
(별도의 알림[소리, 진동, 숫자]이 발생하지 않습니다.)
</div>
<div class="input-group mt-4" role="group">
<div class="input-group-prepend">
<span class="input-group-text">인증 코드</span>
</div>
<input type="number" class="form-control" name='otp' id="otp_code" placeholder="인증 코드">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">취소</button>
<button type="submit" class="btn btn-primary">제출</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
+117 -93
View File
@@ -1,93 +1,117 @@
$(document).ready( function () {
$( "#main_form" ).validate( {
rules: {
username: {
required: true
},
password: {
required: true,
}
},
messages: {
username: {
required: "유저명을 입력해주세요"
},
password: {
required: "비밀번호를 입력해주세요"
}
},
errorElement: "div",
errorPlacement: function ( error, element ) {
// Add the `help-block` class to the error element
error.addClass( "invalid-feedback" );
if ( element.prop( "type" ) === "checkbox" ) {
error.insertAfter( element.parent( "label" ) );
} else {
error.insertAfter( element );
}
},
highlight: function ( element, errorClass, validClass ) {
$( element ).addClass( "is-invalid" ).removeClass( "is-valid" );
},
unhighlight: function (element, errorClass, validClass) {
$( element ).addClass( "is-valid" ).removeClass( "is-invalid" );
}
} );
$( "#main_form" ).submit(function(){
var raw_password = $('#password').val();
var salt = $('#global_salt').val();
var hash_pw = sha512(salt + raw_password + salt);
$.post({
url:'j_login.php',
dataType:'json',
data:{
'username':$('#username').val(),
'password':hash_pw
}
}).then(function(obj){
if(obj.result){
window.location.href = "./";
return;
}
if(!obj.reqOTP){
alert(obj.reason);
return;
}
var $modal = $('#modalOTP').modal();
$modal.on('shown.bs.modal', function(){
$('#otp_code').focus();
});
});
return false;
});
$('#otp_form').submit(function(){
$.post({
url:'oauth_kakao/j_check_OTP.php',
dataType:'json',
data:{
'otp':$('#otp_code').val(),
}
}).then(function(obj){
if(obj.result){
alert(obj.reason);
window.location.href = "./";
return;
}
alert(obj.reason);
if(obj.reset){
$('#modalOTP').modal('hide')
return;
}
});
return false;
})
} );
$(document).ready(function() {
$("#main_form").validate({
rules: {
username: {
required: true
},
password: {
required: true,
}
},
messages: {
username: {
required: "유저명을 입력해주세요"
},
password: {
required: "비밀번호를 입력해주세요"
}
},
errorElement: "div",
errorPlacement: function(error, element) {
// Add the `help-block` class to the error element
error.addClass("invalid-feedback");
if (element.prop("type") === "checkbox") {
error.insertAfter(element.parent("label"));
} else {
error.insertAfter(element);
}
},
highlight: function(element, errorClass, validClass) {
$(element).addClass("is-invalid").removeClass("is-valid");
},
unhighlight: function(element, errorClass, validClass) {
$(element).addClass("is-valid").removeClass("is-invalid");
}
});
$("#main_form").submit(function() {
var raw_password = $('#password').val();
var salt = $('#global_salt').val();
var hash_pw = sha512(salt + raw_password + salt);
$.post({
url: 'j_login.php',
dataType: 'json',
data: {
'username': $('#username').val(),
'password': hash_pw
}
}).then(function(obj) {
if (obj.result) {
window.location.href = "./";
return;
}
if (!obj.reqOTP) {
alert(obj.reason);
return;
}
var $modal = $('#modalOTP').modal();
$modal.on('shown.bs.modal', function() {
$('#otp_code').focus();
});
});
return false;
});
$('#otp_form').submit(function() {
$.post({
url: 'oauth_kakao/j_check_OTP.php',
dataType: 'json',
data: {
'otp': $('#otp_code').val(),
}
}).then(function(obj) {
if (obj.result) {
alert(obj.reason);
window.location.href = "./";
return;
}
alert(obj.reason);
if (obj.reset) {
$('#modalOTP').modal('hide')
return;
}
});
return false;
});
if (document.body.clientWidth < 700) {
var targetWidth = document.body.clientWidth * 0.9;
var scale = targetWidth / 700;
var $map = $('#running_map');
$map.find('.col').css('max-width', targetWidth);
$map.find('.card').css('width', targetWidth);
$map.find('.map-container').css({
'transform-origin': 'top left',
'transform': 'scale({0}, {0})'.format(scale),
'height': 500 * scale,
});
$map.find('.map_body').data('scale', scale);
}
reloadWorldMap({
targetJson: "{0}/j_map_recent.php".format(runningServer.name),
reqType: 'get',
dynamicMapTheme: true,
callback: function(data, rawObject) {
$('#running_map .card-body').html(rawObject.history);
}
});
});