c733e6b200
# Conflicts: # src/main/resources/templates/views/apps/service/oauth2-guide.html
129 lines
6.7 KiB
HTML
129 lines
6.7 KiB
HTML
<!doctype html>
|
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
|
|
|
<head th:fragment="headFragment">
|
|
<title th:text="#{title.html}">개발자 포털</title>
|
|
|
|
<meta content="https://www.eactive.co.kr/" property="og:url"/>
|
|
<meta charset="UTF-8"/>
|
|
|
|
<!-- Favicon (DJB 로고) -->
|
|
<link rel="icon" type="image/png" sizes="32x32" th:href="@{/img/favicon/favicon-32x32.png}"/>
|
|
<link rel="icon" type="image/png" sizes="16x16" th:href="@{/img/favicon/favicon-16x16.png}"/>
|
|
<link rel="shortcut icon" type="image/png" th:href="@{/img/favicon/favicon.png}"/>
|
|
<link rel="apple-touch-icon" sizes="180x180" th:href="@{/img/favicon/apple-touch-icon.png}"/>
|
|
|
|
<!-- 클라이언트 가드 (우클릭 차단 · DevTools 감지). PortalProperty 토글이 하나라도 켜지면 로드 -->
|
|
<th:block th:if="${clientGuardContextmenu or clientGuardDevtools}">
|
|
<script th:inline="javascript">
|
|
window.__CLIENT_GUARD__ = {
|
|
contextmenu: /*[[${clientGuardContextmenu}]]*/ false,
|
|
devtools: /*[[${clientGuardDevtools}]]*/ false
|
|
};
|
|
</script>
|
|
<script th:src="@{/js/djb/client-guard.js}"></script>
|
|
</th:block>
|
|
|
|
<!-- CSRF 토큰 (세션 기반). 정적 JS/AJAX에서 토큰·헤더명을 읽어 사용한다. -->
|
|
<meta name="_csrf" th:content="${_csrf != null ? _csrf.token : ''}"/>
|
|
<meta name="_csrf_header" th:content="${_csrf != null ? _csrf.headerName : 'X-XSRF-TOKEN'}"/>
|
|
|
|
<!-- 익명(비로그인) 세션 keepalive: 로그인/회원가입 등에서 페이지에 머무는 동안 주기적 ping으로
|
|
세션 비활성 타이머를 리셋해 세션 저장 CSRF 토큰·회원가입 본인인증 상태의 만료(10분)를 방지한다.
|
|
탭을 닫으면 ping이 멈춰 정상 만료. 인증 사용자는 헤더의 세션 타이머/heartbeat가 대신 처리한다. -->
|
|
<script sec:authorize="isAnonymous()" th:inline="javascript">
|
|
(function () {
|
|
var PING_URL = /*[[@{/api/session/ping}]]*/ '/api/session/ping';
|
|
var PING_INTERVAL_MS = 4 * 60 * 1000; // 세션 타임아웃(10분)의 절반 이하
|
|
setInterval(function () {
|
|
try {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('GET', PING_URL, true);
|
|
xhr.send();
|
|
} catch (ignore) { /* keepalive 실패는 화면 동작에 영향 없음 */ }
|
|
}, PING_INTERVAL_MS);
|
|
})();
|
|
</script>
|
|
<meta content="max-age=0, public" http-equiv="Cache-Control"/>
|
|
<meta content="index, follow" name="robots"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
|
<meta http-equiv="Cache-Control" content="no-cache">
|
|
<meta http-equiv="Pragma" content="no-cache">
|
|
|
|
<meta http-equiv="Expires" content="0">
|
|
<link rel="stylesheet" type="text/css" th:href="@{/css/all.min.css}">
|
|
<link rel="stylesheet" type="text/css" th:href="@{/css/main.css}">
|
|
<link rel="stylesheet" type="text/css" th:href="@{/css/editor-content.css}">
|
|
<link rel="stylesheet" type="text/css" th:href="@{/css/slick.css}">
|
|
<link rel="stylesheet" type="text/css" th:href="@{/css/daterangepicker.css}">
|
|
|
|
<link rel="stylesheet" th:href="@{/plugins/codemirror/codemirror.css}" type="text/css"/>
|
|
<link rel="stylesheet" th:href="@{/plugins/codemirror/theme/monokai.css}" type="text/css"/>
|
|
<link rel="stylesheet" th:href="@{/plugins/summernote/summernote-lite.css}" type="text/css" />
|
|
<link rel="stylesheet" th:href="@{/plugins/jquery-ui/jquery-ui.min.css}" />
|
|
|
|
<!-- Summernote 스타일 -->
|
|
<style>
|
|
.note-editable img {
|
|
max-width: 100%;
|
|
cursor: pointer;
|
|
}
|
|
/* 코드뷰 모드 가로 사이즈 고정 */
|
|
.note-editor .note-codable {
|
|
width: 100% !important;
|
|
max-width: 100% !important;
|
|
box-sizing: border-box !important;
|
|
resize: vertical !important;
|
|
white-space: pre-wrap !important;
|
|
word-wrap: break-word !important;
|
|
overflow-x: auto !important;
|
|
}
|
|
.note-editor.note-frame {
|
|
overflow: hidden;
|
|
}
|
|
</style>
|
|
|
|
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
|
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
|
<!--[if lt IE 9]>
|
|
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
|
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
|
<![endif]-->
|
|
|
|
<!-- Portal 설정값 전역 노출 -->
|
|
<script th:inline="javascript">
|
|
window.PORTAL_CONFIG = {
|
|
file: {
|
|
maxSize: /*[[${@portalProperties.file.maxSize}]]*/ '8MB',
|
|
maxSizeBytes: /*[[${@portalProperties.file.maxSizeBytes}]]*/ 8388608,
|
|
allowedExtensions: /*[[${@portalProperties.file.allowedExtensions}]]*/ 'pdf,doc,docx,xls,xlsx,ppt,pptx,hwp,gif,jpg,jpeg,png'
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<script th:src="@{/plugins/jquery/jquery-3.7.1.min.js}"></script>
|
|
<script th:src="@{/js/lodash.js}"></script>
|
|
<script th:src="@{/js/common.js}"></script>
|
|
<script th:src="@{/js/moment.min.js}"></script>
|
|
<script th:src="@{/js/daterangepicker.js}"></script>
|
|
<script th:src="@{/plugins/codemirror/codemirror.js}"></script>
|
|
<script th:src="@{/plugins/codemirror/mode/clike.js}"></script>
|
|
<script th:src="@{/plugins/codemirror/mode/javascript.js}"></script>
|
|
<script th:src="@{/plugins/codemirror/addon/display/fullscreen.js}"></script>
|
|
<script th:src="@{/plugins/codemirror/addon/display/placeholder.js}"></script>
|
|
<script th:src="@{/plugins/summernote/summernote-lite.min.js}"></script>
|
|
<script th:src="@{/plugins/summernote/summernote-cleaner.js}"></script>
|
|
<script th:src="@{/plugins/jquery-ui/jquery-ui.min.js}"></script>
|
|
|
|
<!--/* LiveReload (개발 전용): DevTools 가 정적 리소스/템플릿 변경을 감지하면 브라우저를 자동 새로고침한다.
|
|
localhost 외 IP(예: 172.30.1.14)로 접속해도 동작하도록 접속 호스트 기준으로 livereload.js 를 로드한다.
|
|
prod/stage 에는 DevTools 자체가 없으므로(developmentOnly) 개발 프로파일에서만 주입한다. */-->
|
|
<script th:if="${@environment.acceptsProfiles('local_rinjaemac','local')}"
|
|
th:src="|//${#request.serverName}:35729/livereload.js|"></script>
|
|
</head>
|
|
|
|
</html>
|