사용자:Ykhwong/ted-dashboard.js

참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다. 구글 크롬, 파이어폭스, 마이크로소프트 엣지, 사파리: ⇧ Shift 키를 누른 채 "새로 고침" 버튼을 클릭하십시오. 더 자세한 정보를 보려면 위키백과:캐시 무시하기 항목을 참고하십시오.

/* <nowiki> */
/* Currently experimental */
$(function() {
	var containers = {};
	var glLayout = null;
	var pageTabCnt = 0;

	const bodyContent = (mw.config.get("skin") === "cologneblue" ? "article" : "bodyContent");
	const pageTitle = "ted-dashboard";
	const dependencies = [{
			url: 'https://ko.wikipedia.org/w/index.php?title=User:Ykhwong/external/goldenlayout.min.js&action=raw&ctype=text/javascript',
			opt: 'text/javascript'
		},
		{
			url: 'https://ko.wikipedia.org/w/index.php?title=User:Ykhwong/external/goldenlayout-base.css&action=raw&ctype=text/css',
			opt: 'text/css'
		},
		{
			url: 'https://ko.wikipedia.org/w/index.php?title=User:Ykhwong/external/goldenlayout-dark-theme.css&action=raw&ctype=text/css',
			opt: 'text/css'
		}
	];
	const wikiList = [{
			data: 'https://ko.wikipedia.org',
			label: 'ko',
			wdName: 'kowiki'
		},
		{
			data: 'https://en.wikipedia.org',
			label: 'en',
			wdName: 'enwiki'
		},
		{
			data: 'https://ja.wikipedia.org',
			label: 'ja',
			wdName: 'jawiki'
		},
		{
			data: 'https://zh.wikipedia.org',
			label: 'zh',
			wdName: 'zhwiki'
		}
	];
	const wikiBoards = [{
			id: 'ted_village_pump',
			title: '위키백과:사랑방',
			label: '사랑방'
		},
		{
			id: 'ted_help_desk',
			title: '위키백과:질문방',
			label: '질문방'
		}
	];
	const wikiRcTags = [{
			id: 'new-redirect',
			name: 'mw-new-redirect',
			label: '새 넘겨주기'
		},
		{
			id: 'remove-db-tmpl',
			name: '삭제 신청 틀 제거',
			label: '삭제 신청 틀 제거'
		}
	];

	const matchHangul = [
		/* ㅏ,ㅓ,ㅕ,ㅗ,ㅛ,ㅜ,ㅡ,ㅣ,ㅐ,ㅚ,ㅟ */
		// ㅏ 
		{
			key: '[각-갛]',
			val: '간'
		},
		{
			key: '[낙-낳]',
			val: '난'
		},
		{
			key: '[닥-닿]',
			val: '단'
		},
		{
			key: '[락-랗]',
			val: '란'
		},
		{
			key: '[막-맣]',
			val: '만'
		},
		{
			key: '[박-밯]',
			val: '반'
		},
		{
			key: '[삭-샇]',
			val: '산'
		},
		{
			key: '[악-앟]',
			val: '안'
		},
		{
			key: '[작-잫]',
			val: '잔'
		},
		{
			key: '[착-챃]',
			val: '찬'
		},
		{
			key: '[칵-캏]',
			val: '칸'
		},
		{
			key: '[탁-탛]',
			val: '탄'
		},
		{
			key: '[팍-팧]',
			val: '판'
		},
		{
			key: '[학-핳]',
			val: '한'
		},
		{
			key: '[깍-깧]',
			val: '깐'
		},
		{
			key: '[딱-땋]',
			val: '딴'
		},
		{
			key: '[빡-빻]',
			val: '빤'
		},
		{
			key: '[싹-쌓]',
			val: '싼'
		},
		{
			key: '[짝-짷]',
			val: '짠'
		},

		// ㅓ 
		{
			key: '[건-겋]',
			val: '건'
		},
		{
			key: '[넉-넣]',
			val: '넌'
		},
		{
			key: '[덕-덯]',
			val: '던'
		},
		{
			key: '[럭-렇]',
			val: '런'
		},
		{
			key: '[먹-멓]',
			val: '먼'
		},
		{
			key: '[벅-벟]',
			val: '번'
		},
		{
			key: '[석-섷]',
			val: '선'
		},
		{
			key: '[억-엏]',
			val: '언'
		},
		{
			key: '[적-젛]',
			val: '전'
		},
		{
			key: '[척-첳]',
			val: '천'
		},
		{
			key: '[컥-컿]',
			val: '컨'
		},
		{
			key: '[턱-텋]',
			val: '턴'
		},
		{
			key: '[퍽-펗]',
			val: '펀'
		},
		{
			key: '[헉-헣]',
			val: '헌'
		},
		{
			key: '[꺽-껗]',
			val: '껀'
		},
		{
			key: '[떡-떻]',
			val: '떤'
		},
		{
			key: '[뻑-뻫]',
			val: '뻔'
		},
		{
			key: '[썩-쎃]',
			val: '썬'
		},
		{
			key: '[쩍-쩧]',
			val: '쩐'
		},

		// ㅕ
		{
			key: '[견-곃]',
			val: '견'
		},
		{
			key: '[녁-녛]',
			val: '년'
		},
		{
			key: '[뎍-뎧]',
			val: '뎐'
		},
		{
			key: '[력-렿]',
			val: '련'
		},
		{
			key: '[멱-몋]',
			val: '면'
		},
		{
			key: '[벽-볗]',
			val: '변'
		},
		{
			key: '[셕-셯]',
			val: '션'
		},
		{
			key: '[역-옇]',
			val: '연'
		},
		{
			key: '[젹-졓]',
			val: '젼'
		},
		{
			key: '[쳑-쳫]',
			val: '쳔'
		},
		{
			key: '[켝-켷]',
			val: '켠'
		},
		{
			key: '[텩-톃]',
			val: '텬'
		},
		{
			key: '[펵-폏]',
			val: '편'
		},
		{
			key: '[혁-혛]',
			val: '현'
		},
		{
			key: '[껵-꼏]',
			val: '껸'
		},
		{
			key: '[뗙-뗳]',
			val: '뗜'
		},
		{
			key: '[뼉-뼣]',
			val: '뼌'
		},
		{
			key: '[쎡-쎻]',
			val: '쎤'
		},
		{
			key: '[쪅-쪟]',
			val: '쪈'
		},

		// ㅗ
		{
			key: '[곡-곻]',
			val: '곤'
		},
		{
			key: '[녹-놓]',
			val: '논'
		},
		{
			key: '[독-돟]',
			val: '돈'
		},
		{
			key: '[록-롷]',
			val: '론'
		},
		{
			key: '[목-뫃]',
			val: '몬'
		},
		{
			key: '[복-봏]',
			val: '본'
		},
		{
			key: '[속-솧]',
			val: '손'
		},
		{
			key: '[옥-옿]',
			val: '온'
		},
		{
			key: '[족-좋]',
			val: '존'
		},
		{
			key: '[촉-촣]',
			val: '촌'
		},
		{
			key: '[콕-콯]',
			val: '콘'
		},
		{
			key: '[톡-톻]',
			val: '톤'
		},
		{
			key: '[폭-퐇]',
			val: '폰'
		},
		{
			key: '[혹-홓]',
			val: '혼'
		},
		{
			key: '[꼭-꽇]',
			val: '꼰'
		},
		{
			key: '[똑-똫]',
			val: '똔'
		},
		{
			key: '[뽁-뽛]',
			val: '뽄'
		},
		{
			key: '[쏙-쏳]',
			val: '쏜'
		},
		{
			key: '[쪽-쫗]',
			val: '쫀'
		},

		// ㅛ
		{
			key: '[굑-굫]',
			val: '굔'
		},
		{
			key: '[뇩-눃]',
			val: '뇬'
		},
		{
			key: '[됵-둏]',
			val: '됸'
		},
		{
			key: '[룍-룧]',
			val: '룐'
		},
		{
			key: '[묙-묳]',
			val: '묜'
		},
		{
			key: '[뵥-뵿]',
			val: '뵨'
		},
		{
			key: '[쇽-숗]',
			val: '숀'
		},
		{
			key: '[욕-욯]',
			val: '욘'
		},
		{
			key: '[죡-죻]',
			val: '죤'
		},
		{
			key: '[쵹-춓]',
			val: '쵼'
		},
		{
			key: '[쿅-쿟]',
			val: '쿈'
		},
		{
			key: '[툑-툫]',
			val: '툔'
		},
		{
			key: '[푝-푷]',
			val: '푠'
		},
		{
			key: '[횩-훃]',
			val: '횬'
		},
		{
			key: '[꾝-꾷]',
			val: '꾠'
		},
		{
			key: '[뚁-뚛]',
			val: '뚄'
		},
		{
			key: '[뾱-뿋]',
			val: '뾴'
		},
		{
			key: '[쑉-쑣]',
			val: '쑌'
		},
		{
			key: '[쬭-쭇]',
			val: '쬰'
		},

		// ㅜ
		{
			key: '[국-궇]',
			val: '군'
		},
		{
			key: '[눅-눟]',
			val: '눈'
		},
		{
			key: '[둑-둫]',
			val: '둔'
		},
		{
			key: '[룩-뤃]',
			val: '룬'
		},
		{
			key: '[묵-뭏]',
			val: '문'
		},
		{
			key: '[북-붛]',
			val: '분'
		},
		{
			key: '[숙-숳]',
			val: '순'
		},
		{
			key: '[욱-웋]',
			val: '운'
		},
		{
			key: '[죽-줗]',
			val: '준'
		},
		{
			key: '[축-춯]',
			val: '춘'
		},
		{
			key: '[쿡-쿻]',
			val: '쿤'
		},
		{
			key: '[툭-퉇]',
			val: '툰'
		},
		{
			key: '[푹-풓]',
			val: '푼'
		},
		{
			key: '[훅-훟]',
			val: '훈'
		},
		{
			key: '[꾹-꿓]',
			val: '꾼'
		},
		{
			key: '[뚝-뚷]',
			val: '뚠'
		},
		{
			key: '[뿍-뿧]',
			val: '뿐'
		},
		{
			key: '[쑥-쑿]',
			val: '쑨'
		},
		{
			key: '[쭉-쭣]',
			val: '쭌'
		},

		// ㅡ
		{
			key: '[극-긓]',
			val: '근'
		},
		{
			key: '[늑-늫]',
			val: '는'
		},
		{
			key: '[득-듷]',
			val: '든'
		},
		{
			key: '[륵-릏]',
			val: '른'
		},
		{
			key: '[믁-믛]',
			val: '믄'
		},
		{
			key: '[븍-븧]',
			val: '븐'
		},
		{
			key: '[슥-슿]',
			val: '슨'
		},
		{
			key: '[윽-읗]',
			val: '은'
		},
		{
			key: '[즉-즣]',
			val: '즌'
		},
		{
			key: '[측-츻]',
			val: '츤'
		},
		{
			key: '[큭-킇]',
			val: '큰'
		},
		{
			key: '[특-틓]',
			val: '튼'
		},
		{
			key: '[픅-픟]',
			val: '픈'
		},
		{
			key: '[흑-흫]',
			val: '흔'
		},
		{
			key: '[끅-끟]',
			val: '끈'
		},
		{
			key: '[뜩-띃]',
			val: '뜬'
		},
		{
			key: '[쁙-쁳]',
			val: '쁜'
		},
		{
			key: '[쓱-씋]',
			val: '쓴'
		},
		{
			key: '[쯕-쯯]',
			val: '쯘'
		},

		// ㅣ
		{
			key: '[긱-깋]',
			val: '긴'
		},
		{
			key: '[닉-닣]',
			val: '닌'
		},
		{
			key: '[딕-딯]',
			val: '딘'
		},
		{
			key: '[릭-맇]',
			val: '린'
		},
		{
			key: '[믹-밓]',
			val: '민'
		},
		{
			key: '[빅-빟]',
			val: '빈'
		},
		{
			key: '[식-싷]',
			val: '신'
		},
		{
			key: '[익-잏]',
			val: '인'
		},
		{
			key: '[직-짛]',
			val: '진'
		},
		{
			key: '[칙-칳]',
			val: '친'
		},
		{
			key: '[킥-킿]',
			val: '킨'
		},
		{
			key: '[틱-팋]',
			val: '틴'
		},
		{
			key: '[픽-핗]',
			val: '핀'
		},
		{
			key: '[힉-힣]',
			val: '힌'
		},
		{
			key: '[끽-낗]',
			val: '낀'
		},
		{
			key: '[띡-띻]',
			val: '띤'
		},
		{
			key: '[삑-삫]',
			val: '삔'
		},
		{
			key: '[씩-앃]',
			val: '씬'
		},
		{
			key: '[찍-찧]',
			val: '찐'
		},

		// ㅐ
		{
			key: '[객-갷]',
			val: '갠'
		},
		{
			key: '[낵-냏]',
			val: '낸'
		},
		{
			key: '[댁-댛]',
			val: '댄'
		},
		{
			key: '[랙-랳]',
			val: '랜'
		},
		{
			key: '[맥-맿]',
			val: '맨'
		},
		{
			key: '[백-뱋]',
			val: '밴'
		},
		{
			key: '[색-샣]',
			val: '샌'
		},
		{
			key: '[액-앻]',
			val: '앤'
		},
		{
			key: '[잭-쟇]',
			val: '잰'
		},
		{
			key: '[책-챟]',
			val: '챈'
		},
		{
			key: '[캑-캫]',
			val: '캔'
		},
		{
			key: '[택-탷]',
			val: '탠'
		},
		{
			key: '[팩-퍃]',
			val: '팬'
		},
		{
			key: '[핵-햏]',
			val: '핸'
		},
		{
			key: '[깩-꺃]',
			val: '깬'
		},
		{
			key: '[땍-땧]',
			val: '땐'
		},
		{
			key: '[빽-뺗]',
			val: '뺀'
		},
		{
			key: '[쌕-쌯]',
			val: '쌘'
		},
		{
			key: '[짹-쨓]',
			val: '짼'
		},

		// ㅚ
		{
			key: '[괵-굏]',
			val: '괸'
		},
		{
			key: '[뇍-뇧]',
			val: '뇐'
		},
		{
			key: '[됙-됳]',
			val: '된'
		},
		{
			key: '[뢱-룋]',
			val: '뢴'
		},
		{
			key: '[뫽-묗]',
			val: '묀'
		},
		{
			key: '[뵉-뵣]',
			val: '뵌'
		},
		{
			key: '[쇡-쇻]',
			val: '쇤'
		},
		{
			key: '[왹-욓]',
			val: '왼'
		},
		{
			key: '[죅-죟]',
			val: '죈'
		},
		{
			key: '[쵝-쵷]',
			val: '쵠'
		},
		{
			key: '[쾩-쿃]',
			val: '쾬'
		},
		{
			key: '[퇵-툏]',
			val: '퇸'
		},
		{
			key: '[푁-푛]',
			val: '푄'
		},
		{
			key: '[획-횧]',
			val: '횐'
		},
		{
			key: '[꾁-꾛]',
			val: '꾄'
		},
		{
			key: '[뙥-뙿]',
			val: '뙨'
		},
		{
			key: '[뾕-뾯]',
			val: '뾘'
		},
		{
			key: '[쐭-쑇]',
			val: '쐰'
		},
		{
			key: '[쬑-쬫]',
			val: '쬔'
		},

		// ㅟ
		{
			key: '[귁-귛]',
			val: '귄'
		},
		{
			key: '[뉙-뉳]',
			val: '뉜'
		},
		{
			key: '[뒥-뒿]',
			val: '뒨'
		},
		{
			key: '[뤽-륗]',
			val: '륀'
		},
		{
			key: '[뮉-뮣]',
			val: '뮌'
		},
		{
			key: '[뷕-뷯]',
			val: '뷘'
		},
		{
			key: '[쉭-슇]',
			val: '쉰'
		},
		{
			key: '[윅-윟]',
			val: '윈'
		},
		{
			key: '[쥑-쥫]',
			val: '쥔'
		},
		{
			key: '[췩-츃]',
			val: '췬'
		},
		{
			key: '[퀵-큏]',
			val: '퀸'
		},
		{
			key: '[튁-튛]',
			val: '튄'
		},
		{
			key: '[퓍-퓧]',
			val: '퓐'
		},
		{
			key: '[휙-휳]',
			val: '휜'
		},
		{
			key: '[뀍-뀧]',
			val: '뀐'
		},
		{
			key: '[뛱-뜋]',
			val: '뛴'
		},
		{
			key: '[쀡-쀻]',
			val: '쀤'
		},
		{
			key: '[쒹-쓓]',
			val: '쒼'
		},
		{
			key: '[쮝-쮷]',
			val: '쮠'
		},
	];

	const tabCSS = `
<style type="text/css">
  /*TAB CSS*/
  ul.tabs1,
  ul.tabs2,
  ul.tabs3 {
    margin: 0;
    padding: 0;
    /*float: left;*/
    list-style: none;
    height: 32px;
    /*--Set height of tabs--*/
    border-bottom: 1px solid #999;
    border-left: 1px solid #999;
    width: 100%;
  }

  ul.tabs1 li,
  ul.tabs2 li,
  ul.tabs3 li {
    float: left;
    margin: 0;
    padding: 0;
    height: 31px;
    /*--Subtract 1px from the height of the unordered list--*/
    line-height: 31px;
    /*--Vertically aligns the text within the tab--*/
    border: 1px solid #999;
    border-left: none;
    margin-bottom: -1px;
    /*--Pull the list item down 1px--*/
    overflow: hidden;
    position: relative;
    background: #e0e0e0;
  }

  ul.tabs1 li a,
  ul.tabs2 li a,
  ul.tabs3 li a {
    text-decoration: none;
    color: #000;
    display: block;
    padding: 0 20px;
    /*--Gives the bevel look with a 1px white border inside the list item--*/
    border: 1px solid #fff;
    outline: none;
  }

  ul.tabs1 li a:hover,
  ul.tabs2 li a:hover,
  ul.tabs3 li a:hover {
    background: #ccc;
  }

  html ul.tabs1 li.active,
  html ul.tabs1 li.active a:hover,
  html ul.tabs2 li.active,
  html ul.tabs2 li.active a:hover,
  html ul.tabs3 li.active,
  html ul.tabs3 li.active a:hover {
    /*--Makes sure that the active tab does not listen to the hover properties--*/
    background: #fff;
    /*--Makes the active tab look like it's connected with its content--*/
    border-bottom: 1px solid #fff;
  }

  /*Tab Conent CSS*/
  .tab_container1,
  .tab_container2,
  .tab_container3 {
    border: 1px solid #999;
    border-top: none;
    overflow: hidden;
    clear: both;
    float: left;
    width: 100%;
    background: #fff;
  }

  .tab_content1,
  .tab_content2,
  .tab_content3 {
    padding: 20px;
  }
</style>
`;

	const contribComponentTabs = [{
			name: "searchView",
			func: function() {
				setSearchViewLayout();
			}
		},
		{
			name: "pageView",
			func: function() {
				setPageViewLayout();
			}
		},
		{
			name: "recentChangesView",
			func: function() {
				setRecentChangesViewLayout();
			}
		},
		{
			name: "translationToolView",
			func: function() {
				setTranslationToolViewLayout();
			}
		},
		{
			name: "bulletinBoardView",
			func: function() {
				setBulletinBoardViewLayout();
			}
		}
	];

	const contentPerTab = [{
			type: 'column',
			content: [{
					type: 'component',
					componentName: 'searchView',
					componentState: {
						label: 'B'
					},
					title: '검색',
					height: 48,
					reorderEnabled: false,
					isClosable: false
				},
				{
					type: 'component',
					componentName: 'pageView',
					componentState: {
						label: 'C'
					},
					title: '문서 편집',
					reorderEnabled: false,
					isClosable: false
				}
			]
		},
		{
			type: 'column',
			content: [{
					type: 'component',
					componentName: 'recentChangesView',
					componentState: {
						label: 'B'
					},
					title: '최근 바뀜',
					height: 48,
					reorderEnabled: false,
					isClosable: false
				},
				{
					type: 'component',
					componentName: 'translationToolView',
					componentState: {
						label: 'C'
					},
					title: '번역',
					reorderEnabled: false,
					isClosable: false
				},
				{
					type: 'component',
					componentName: 'bulletinBoardView',
					componentState: {
						label: 'C'
					},
					title: '게시판',
					reorderEnabled: false,
					isClosable: false
				}
			]
		}
	];

	const glConfig = {
		settings: {
			showPopoutIcon: false,
			showMaximiseIcon: false,
			showCloseIcon: false
		},
		dimensions: {
			borderWidth: 5,
			minItemHeight: 10,
			minItemWidth: 10,
			headerHeight: 20,
			dragProxyWidth: 300,
			dragProxyHeight: 200
		},
		content: [{
			isClosable: false,
			type: "stack",
			title: "area",
			content: [{
				name: "tab1",
				title: "기여 모드",
				reorderEnabled: false,
				type: "row",
				componentName: "test",
				isClosable: false,
				content: contentPerTab
			}, {
				title: "모니터링",
				type: "row",
				reorderEnabled: false,
				componentName: "test2",
				isClosable: false
			}]
		}]
	};

	var editTabStatusInfo = {};

	const setEditTabStatus = function(tabNo, config) {
		if (!editTabStatusInfo[tabNo]) {
			editTabStatusInfo[tabNo] = {
				isPreviewMode: false,
				isPreviewCompleted: false,
				isAnalyzed: false
			};
		}

		if (typeof config.isPreviewMode !== 'undefined') {
			editTabStatusInfo[tabNo].isPreviewMode = config.isPreviewMode;
		}

		if (typeof config.isPreviewCompleted !== 'undefined') {
			editTabStatusInfo[tabNo].isPreviewCompleted = config.isPreviewCompleted;
		}

		if (typeof config.isAnalyzed !== 'undefined') {
			editTabStatusInfo[tabNo].isAnalyzed = config.isAnalyzed;
		}
	};

	const getEditTabStatus = function(tabNo) {
		return editTabStatusInfo[tabNo];
	};

	const showMessage = function(msg, title) {
		mw.notify(msg, {
			title: title
		});		
	};

	const findLabelByDataFromWikilist = function(data) {
		for (var i = 0; i < wikiList.length; i++) {
			if (data === wikiList[i].data) {
				return wikiList[i].label;
			}
		}
		return null;
	};

	const findWdNameByLabelFromWikilist = function(label) {
		for (var i = 0; i < wikiList.length; i++) {
			if (label === wikiList[i].label) {
				return wikiList[i].wdName;
			}
		}
		return null;
	};

	const encodeHTMLEntities = function(text) {
		return $("<textarea/>").text(text).html();
	};

	const setSource = function(title, wikiUrl, id) {
		const params = {
				action: 'parse',
				prop: 'wikitext',
				page: title
			},
			api = new mw.ForeignApi(wikiUrl + '/w/api.php');
		api.get(params).done(function(data) {
			$("#" + id).val(data.parse.wikitext["*"]);
		});
	};

	const setCleanSource = function(title, wikiUrl, id) {
		const params = {
				action: 'query',
				prop: 'extracts',
				titles: title
			},
			api = new mw.ForeignApi(wikiUrl + '/w/api.php');
		api.get(params).done(function(data) {
			const htmltext = data.query.pages[Object.keys(data.query.pages)[0]].extract
				.replace(/<b>(.*?)<\/b>/mg, "'''$1'''")
				.replace(/(<h2>)(.*?)(<\/h2>)/mg, "$1== $2 ==$3")
				.replace(/(<h3>)(.*?)(<\/h3>)/mg, "$1=== $2 ===$3")
				.replace(/(<h4>)(.*?)(<\/h4>)/mg, "$1==== $2 ====$3")
				.replace(/(<h5>)(.*?)(<\/h5>)/mg, "$1===== $2 =====$3")
				.replace(/<li>/mg, "<li>*&nbsp;")
				.replace(/<p>/mg, "<p>\n");
			const wikitext = $(htmltext).text().trim().replace(/\n{3,}/mg, "\n\n");
			$("#" + id).val(wikitext);
		});
	};

	const setTitle = function() {
		const params = {
				action: 'parse',
				text: '{{int:Interlanguage-link-sitename-wikipedia}}',
				contentmodel: 'wikitext'
			},
			api = new mw.ForeignApi('/w/api.php');
		api.get(params).done(function(data) {
			document.title = pageTitle + ' - ' + $(data.parse.text["*"]).find("p").text();
		});
	};

	const setSections = function(title, wikiUrl, id) {
		const params = {
				action: 'parse',
				prop: 'sections',
				page: title
			},
			api = new mw.ForeignApi(wikiUrl + '/w/api.php');

		api.get(params).done(function(data) {
			const sections = data.parse.sections.reverse();
			var sectionData = "";
			for (var i = 0; i < sections.length; i++) {
				const toclevel = sections[i].toclevel;
				const linkAnchor = encodeURIComponent(sections[i].linkAnchor);
				const line = encodeHTMLEntities(sections[i].line);
				var summaryInfo = "";
				if (sections[i].extensionData) {
					if (sections[i].extensionData['DiscussionTools-html-summary']) {
						summaryInfo = '&nbsp;' + sections[i].extensionData['DiscussionTools-html-summary'];
					}
				}
				if (toclevel !== 1) {
					continue;
				}
				sectionData += '<a href="' + wikiUrl + '/wiki/' + encodeURIComponent(title) + '#' + linkAnchor + '" target="_blank">' + line + '</a>' + summaryInfo + '<br>';
			}
			$('#' + id).html(sectionData);
		});
	};

	const setRecentChangesFeed = function(wikiUrl, tag, id) {
		const params = {
				action: 'query',
				list: 'recentchanges',
				rclimit: '12',
				format: 'json'
			},
			api = new mw.ForeignApi(wikiUrl + '/w/api.php');

		if (tag !== null) {
			params.rctag = tag;
		}

		api.get(params).done(function(data) {
			const feed = data.query.recentchanges;
			var content = "";
			for (var i = 0; i < feed.length; i++) {
				var type = feed[i].type;
				var title = '<a href="' + wikiUrl + '/wiki/Special:Diff/' + feed[i].revid + '" target="_blank">차이</a>&nbsp;' + feed[i].title;
				content += title + "&nbsp;[" + type + "]<br>";
			}
			$('#' + id).html(content);
		});
	};

	const setSitelink = function(fromSite, fromTitle, toSite, toTitle) {
		const wikidataAPI = new mw.ForeignApi('https://www.wikidata.org/w/api.php');
		const json = {
			action: 'wbsetsitelink',
			site: fromSite,
			title: fromTitle,
			linksite: toSite,
			linktitle: toTitle
		};
		wikidataAPI.postWithToken('csrf', json, {
			success: function(e) {
				if (e.error && e.error.info) {
					var msg = "";
					if (e.error.messages[1] && e.error.messages[1].html["*"]) {
						msg = $('<p>' + e.error.messages[1].html["*"] + '</p>').text();
					} else {
						msg = e.error["*"];
					}
					showMessage(msg, e.error.info);
					return;
				}
				showMessage('Wikidata link succeeded.', 'Success');
			}
		});
	};

	const previewPage = function(title, wikiUrl, pageText, tabCnt) {
		const api = new mw.ForeignApi(wikiUrl + '/w/api.php');
		const previewId = '#ted_preview_' + tabCnt;
		const editId = '#ted_edit_' + tabCnt;
		const myJson = {
			format: 'json',
			action: 'parse',
			preview: true,
			disableeditsection: true,
			pst: true,
			title: title,
			text: pageText,
			prop: 'text|categorieshtml|langlinks'
		};
		$(editId).hide();
		$(previewId).css('display', 'inline-block');
		$(previewId).html("<p>미리 보기 생성 중</p>").show();
		api.postWithEditToken(myJson).then(function(data) {
			const htmlText = data.parse.text['*'] + data.parse.categorieshtml["*"];
			$(previewId).html(htmlText);
			setEditTabStatus(tabCnt, {
				isPreviewCompleted: true
			});
		});
	};

	const togglePreview = function(title, wikiUrl, pageText, tabCnt) {
		const tabStat = getEditTabStatus(tabCnt);
		if (tabStat.isPreviewMode === false) {
			$('#ted_prev_edit_toggle_' + tabCnt + ' .oo-ui-labelElement-label').text('편집 모드');
			previewPage(title, wikiUrl, pageText, tabCnt);
			setEditTabStatus(tabCnt, {
				isPreviewMode: true,
				isPreviewCompleted: false,
				isAnalyzed: false
			});
		} else {
			const previewId = '#ted_preview_' + tabCnt;
			const editId = '#ted_edit_' + tabCnt;
			$('#ted_prev_edit_toggle_' + tabCnt + ' .oo-ui-labelElement-label').text('미리 보기');
			$(editId).show();
			$(previewId).hide();
			setEditTabStatus(tabCnt, {
				isPreviewMode: false,
				isPreviewCompleted: false,
				isAnalyzed: false
			});
		}
	};

	const submitPage = function(title, wikiUrl, pageText) {
		const api = new mw.ForeignApi(wikiUrl + '/w/api.php');
		const myJson = {
			action: 'edit',
			summary: '',
			text: pageText,
			title: title
		};

		api.postWithEditToken(myJson).then(function(e) {
			if (e.edit.result === 'Failure') {
				if (e.edit.captcha && e.edit.captcha.id) {
					const captchaUrl = wikiUrl + '/w/index.php?title=Special:Captcha/image&wpCaptchaId=' + e.edit.captcha.id;
					captchaId = e.edit.captcha.id;
					OO.ui.prompt(
						new OO.ui.HtmlSnippet('<img src=' + captchaUrl + ' height=72>'), {
							textInput: {
								placeholder: 'Enter CAPTCHA'
							}
						}).done(function(result) {
						if (result && /\S/.test(result)) {
							myJson.captchaid = captchaId;
							myJson.captchaword = result;
							api.postWithEditToken(myJson).then(function(e) {
								if (e.edit.result === 'Failure') {
									showMessage('Failed to submit the page.',  'Failed');
								} else {
									showMessage('Page submitted.', 'Edited');
								}
							});
						}
					});
					showMessage('Failed to submit the page.', 'Failed');
				} else {
					showMessage('Failed to submit the page.', 'Failed');
				}
			} else {
				showMessage('Page submitted.', 'Edited');
			}
		});
	};

	const insertAtCursor = function(myField, myValue) {
		if (document.selection) {
			myField.focus();
			sel = document.selection.createRange();
			sel.text = myValue;
		} else if (myField.selectionStart || myField.selectionStart == '0') {
			var startPos = myField.selectionStart;
			var endPos = myField.selectionEnd;
			myField.value = myField.value.substring(0, startPos) +
				myValue +
				myField.value.substring(endPos, myField.value.length);
		} else {
			myField.value += myValue;
		}
		myField.focus();
	};

	window.copyToClipboard = function(text, plain, id) {
		if (!/\S/.test(text)) {
			return;
		}
		const elem = document.createElement('textarea');
		text = plain ? text : text.replace(/^\(/, "").replace(/\)$/, "");
		if (plain) {
			// do nothing
		} else if (/^틀:/.test(text)) {
			text = "{{" + text.replace(/^틀:/, "") + "}}";
		} else {
			text = "[[" + text + "]]";
		}
		elem.value = text;
		document.body.appendChild(elem);
		elem.select();
		document.execCommand('copy');
		document.body.removeChild(elem);
		insertAtCursor(document.getElementById(id.replace(/^#/, '')), text);
	};

	const copyLinks = function(previewId, tabCnt) {
		var cats = "";
		const tabEditId = '#tab_edit_' + tabCnt + '_import_textarea';
		$(previewId + " .koTitleGrp").each(function(idx) {
			var cat = $(this).text().replace(/^\(/, "").replace(/\)$/, "");
			if (!/^분류:/.test(cat)) {
				cats += "* [[" + cat + "]]\n";
			}
		});
		copyToClipboard(cats, true, tabEditId);
	};

	const copyCategories = function(previewId, tabCnt) {
		var cats = "";
		const tabEditId = '#tab_edit_' + tabCnt + '_import_textarea';
		$(previewId + " #mw-normal-catlinks sup").each(function(idx) {
			cats += "[[" + $(this).text().replace(/^\(/, "").replace(/\)$/, "") + "]]\n";
		});
		copyToClipboard(cats, true, tabEditId);
	};

	const copyExtLinks = function(enSource, previewId, tabCnt) {
		var hold = false;
		var resultDat = "";
		const tabEditId = '#tab_edit_' + tabCnt + '_import_textarea';
		for (var i = 0; i < enSource.split(/\n/).length; i++) {
			var ln = enSource.split(/\n/)[i];
			if (hold) {
				if (/^\s*\[\[\s*category/i.test(ln)) {
					break;
				}
				if (
					(!/^\s*\{\{/.test(ln) || /^\s*\{\{\s*authority(\s|_)*control\s*\}\}\s*$/i.test(ln) ||
						/^\s*\{\{\s*taxonbar\s*(\||\}\})/i.test(ln)
					) &&
					/\S/.test(ln)) {
					resultDat += ln + "\n";
					continue;
				}
			}
			if (/^\s*==\s*external\s+links\s*==/i.test(ln)) {
				hold = true;
				continue;
			}
		}
		if (/\S/.test(resultDat)) {
			if (!/== *외부 링크 *==/.test($("#ta1").val())) {
				resultDat = "== 외부 링크 ==" + "\n" + resultDat;
			}
		}
		copyToClipboard(resultDat, true, tabEditId);
	};

	const analyzePage = function(previewId, wikiUrl, tabCnt) {
		var titles = [];
		const onlyUnique = function(value, index, self) {
			return self.indexOf(value) === index;
		};

		$(previewId + ' a, ' + previewId + ' #catlinks a').each(function(index) {
			if ($(this).hasClass('mw-redirect')) {
				$(this).append('<sup style="user-select: none;">[Redirect]</sup>');
			}

			if (
				$(this).attr('title') &&
				!$(this).attr('aria-label') &&
				!/Edit section: /.test($(this).attr('title'))
			) {
				titles.push($(this).attr('title'));
			}
		});
		titles = titles.filter(onlyUnique);

		const api = new mw.ForeignApi(wikiUrl + '/w/api.php');
		const runApi = function(params) {
			api.get(params).done(function(data) {
				if (data.query.pages && Object.values(data.query.pages)[0].langlinks) {
					var title = Object.values(data.query.pages)[0].title;
					var langLinks = Object.values(data.query.pages)[0].langlinks;
					var koTitle = "";
					var zhFound = false;
					var jaFound = false;
					var koFound = false;
					for (var i2 = 0; i2 < langLinks.length; i2++) {
						if (langLinks[i2].lang === "ko") {
							koFound = true;
							koTitle = langLinks[i2]["*"];
							langFound = true;
							if (zhFound && jaFound && koTitle !== "") {
								break;
							}
							continue;
						}
						if (langLinks[i2].lang === "zh") {
							zhFound = true;
							if (zhFound && jaFound && koTitle !== "") {
								break;
							}
							continue;
						}
						if (langLinks[i2].lang === "ja") {
							jaFound = true;
							if (zhFound && jaFound && koTitle !== "") {
								break;
							}
							continue;
						}
					}
					if (data.query.redirects && (data.query.redirects)[0].from) {
						title = Object.values(data.query.redirects)[0].from;
					}
					$(previewId + ' a, ' + previewId + ' #catlinks a').each(function(idx) {
						if ($(this).prop("title") === title && !$(this).data("koUsed")) {
							$(this).data("koUsed", "true");
							if (koTitle !== "") {
								const tabEditId = '#tab_edit_' + tabCnt + '_import_textarea';
								$(this).append('<a href="javascript:void(null);" onClick="copyToClipboard(this.innerText, false, \'' + tabEditId + '\');" class="koTitleGrp" style="color: green;"><sup style="user-select: none;">(' + koTitle + ')</sup></a>');
							}
							if (zhFound) {
								$(this).append('<a href="javascript:void(null);"><sub style="user-select: none; color: green;">[Z]</sub></a>');
							}
							if (jaFound) {
								$(this).append('<a href="javascript:void(null);"><sub style="user-select: none; color: green;">[J]</sub></a>');
							}
							if (koFound) {
								$(this).append('<a href="javascript:void(null);"><sub style="user-select: none; color: green;">[K]</sub></a>');
							}
							if (zhFound && jaFound && !koFound) {
								$(this).append('<a href="javascript:void(null);"><sub style="user-select: none; color: green;">[-]</sub></a>');
							}
							if (koTitle === "" && !zhFound && !jaFound) {
								$(this).append('<a href="javascript:void(null);"><sub style="user-select: none; color: green;">[*' + langLinks.length + ']</sub></a>');
							}
						}
					});
				}
			});
		};

		for (var i = 0; i < titles.length; i++) {
			const params = {
					action: 'query',
					prop: 'langlinks',
					titles: titles[i],
					lllimit: '500'
				};
			runApi(params);
		}
		setEditTabStatus(tabCnt, {
			isAnalyzed: true
		});
	};

	const initDashboard = function() {
		if ($("#tedDashboardArea").length > 0) {
			return;
		}

		document.getElementsByTagName("h1")[0].textContent = pageTitle;
		setTitle();
		document.getElementById(bodyContent).innerHTML = '<div id="tedDashboardArea"></div>';
		for (var i = 0; i < dependencies.length; i++) {
			mw.loader.load(dependencies[i].url, dependencies[i].opt);
		}

		$("body").append(tabCSS);

		var wait_timer = 1;

		function setDashboard() {
			setTimeout(function() {
				wait_timer++;
				if (wait_timer < 10) {
					if (typeof GoldenLayout !== 'undefined') {
						createDashboard();
						return;
					}
					setDashboard();
				}
			}, 500);
		}

		mw.loader.using(["oojs-ui-core", "oojs-ui-widgets", "oojs-ui-toolbars", "oojs-ui-windows", "mediawiki.ForeignApi"]).done(function() {
			setDashboard();
		});
	};

	const createTranslation = function(text1, sourceLang, targetLang, id) {
		(async () => {
			var result = "";
			var prechunks = "";
			var chunks = "";
			var texts = text1.split(/\n/);

			// Check whether if a line length exceeds > 5000
			for (var i = 0; i < texts.length; i++) {
				if (texts[i].length > 5000) {
					showMessage("한 줄의 길이가 5000 크기가 넘어가므로 번역할 수 없습니다.", "번역 실패");
					return;
				}
			}

			const addText = function(data) {
				result += "\n";
			};

			for (var i2 = 0; i2 < texts.length; i++) {
				if (!/\S/.test(texts[i2])) {
					addText(texts[i2]);
					continue;
				}
				chunks += texts[i2] + "\n";
				if (chunks.length > 5000) {
					var newChunkArr = chunks.split(/\n/);
					var newChunk = "";
					newChunkArr.pop();
					for (var i3 = 0; i3 < newChunkArr.length; i3++) {
						newChunk += newChunkArr[i3] + "\n";
					}
					await translate(newChunk, sourceLang, targetLang).then(function(text) {
						text = text.replace(/\n/mg, "\n\n").trim();
						addText(text);
					});
					chunks = texts[i2] + "\n";
				}
			}
			if (chunks.length > 0) {
				await translate(chunks, sourceLang, targetLang).then(function(text) {
					addText(text);
				});
			}

			if (targetLang === 'ko') {
				result = replaceStrForTranslation(result);
			}
			$('#' + id).val(result.trim().replace(/\n{3,}/mg, "\n\n"));
		})();
	};

	const translate = function(text, sourceLang, targetLang) {
		const source = sourceLang ?? 'en';
		const target = targetLang ?? 'ko';

		const url = 'https://translate.googleapis.com/translate_a/single?client=gtx&sl=' +
			source + "&tl=" + target + "&dt=t&q=" + encodeURIComponent(text);

		const parseJSON = function(txt) {
			return JSON.parse(txt.split(',').map(x => x || 'null').join(','));
		};

		const joinSnippets = function(json) {
			return json[0].map(x => x[0]).join('');
		};

		return fetch(url)
			.then(res => res.text())
			.then(text => joinSnippets(parseJSON(text)))
			.catch(reason => console.log('Google Translate: ' + reason));
	};

	const replaceStrForTranslation = function(txt) {
		var result = "";
		txt = txt
			.replace(/ 그렇습니다(\.|<|\()/g, ' 그렇다$1')
			.replace(/좁습니다(\.|<|\()/g, '좁다$1')
			.replace(/넓습니다(\.|<|\()/g, '넓다$1')
			.replace(/졌습니다(\.|<|\()/g, '졌다$1')
			.replace(/([있없갔었였했았렸렀짧꼈겠켰됐났쳤겼같높낮녔많깝왔썼잤랐렵냈뒀혔롭럽좋싫췄섰웠맵])습니다(\.|<|\()/g, '$1다$2')
			.replace(/ (우세|유능|무능|무능력|촉촉|익숙|순|편안|편리|간편|중요|확실|불확실|필요|불편|편|동일|암울|우울|귀중|소중|모호|애매|애매모호|유명|저명|다양|잔인|강인|상이|편협|협소|광대|광활|불과|간결|가능|불가|불가능|흔|가득|독특|특별|적합|부적합|적절|부적절|유사|유연|뻣뻣|행복|비슷|분명|곤란|불안)합니다(\.|<|\()/g, ' $1하다$2')
			//.replace(/이기도 합니다(\.|<|\()/g,'이기도 하다$1') // TO-DO: Fix 학생이기도 합니다(학생이기도 하다) and 쓰이기도 합니다(쓰이기도 한다)
			.replace(/ 아닙니다(\.|<|\()/g, ' 아니다$1')
			.replace(/ 보입니다(\.|<|\()/g, ' 보인다$1')
			.replace(/ 줄입니다(\.|<|\()/g, ' 줄인다$1')
			.replace(/ 높입니다(\.|<|\()/g, ' 높인다$1')
			.replace(/ 작습니다(\.|<|\()/g, ' 작다$1')
			.replace(/ 바람직합니다(\.|<|\()/g, ' 바람직하다$1')
			.replace(/ 저렴합니다(\.|<|\()/g, ' 저렴하다$1')
			//.replace(/ 절입니다(\.|<|\()/g,' 절인다$1') // TO-DO: Fix noun(절) and verb(절)
			.replace(/들입니다(\.|<|\()/g, '들인다$1') // e.g, 들인다, 곁들인다
			.replace(/입니다(\.|<|\()/g, '이다$1')
			.replace(/쁩니다(\.|<|\()/g, '쁘다$1') // e.g, 기쁩니다, 예쁩니다
			.replace(/쉽니다(\.|<|\()/g, '쉰다$1') // e.g, 내쉽니다
			.replace(/쉽습니다(\.|<|\()/g, '쉽다$1') // e.g, 쉽습니다, 아쉽습니다
			.replace(/ 부릅니다(\.|<|\()/g, ' 부른다$1')
			.replace(/ 바릅니다(\.|<|\()/g, ' 바른다$1')
			.replace(/릅니다(\.|<|\()/g, '르다$1') // e.g, 푸르릅니다, 다릅니다
			.replace(/ 깁니다(\.|<|\()/g, ' 길다$1'); // but note: 굶깁니다 → 굶긴다

		for (var i = 0; i < txt.split(/\n/).length; i++) {
			var line = txt.split(/\n/)[i];
			if (!/니다(\.|<|\()/.test(line)) {
				result += line + "\n";
				continue;
			}
			// e.g, 엮습니다 → 엮는다
			if (/습니다(\.|<|\()/.test(line)) {
				line = line.replace(/습니다(\.|<|\()/g, '는다$1');
			}
			if (/[가-힣]니다(\.|<|\()/.test(line)) {
				for (var i2 = 0; i2 < matchHangul.length; i2++) {
					var key = matchHangul[i2].key;
					var val = matchHangul[i2].val;
					line = line.replace(new RegExp(key + "니다(\\.|<|\\()", "g"), val + "다$1");
				}
			}
			result += line + "\n";
		}
		return result.trim() + "\n";
	};

	const setTranslationToolViewLayout = function() {
		var container = containers.translationToolView;
		var translation_content_area = '<textarea id="translation_area" style="width: 100%; height: 100px;"></textarea>';
		var button1 = new OO.ui.ButtonWidget({
			label: '번역',
			title: '번역'
		});
		var button2 = new OO.ui.ButtonWidget({
			label: '원문 가져오기',
			title: '원문 가져오기'
		});

		var fromLang = new OO.ui.TextInputWidget({
			value: 'en',
			placeholder: '출발지 언어 (예: en)'
		});
		var toLang = new OO.ui.TextInputWidget({
			value: 'ko',
			placeholder: '도착지 언어 (예: ko)'
		});

		button1.on('click', function() {
			var text1 = $('#translation_area').val();
			var sourceLang = fromLang.getValue();
			var targetLang = toLang.getValue();
			if (!/\S/.test(text1)) {
				showMessage('번역할 내용이 없습니다', '번역 실패');
				return;
			}
			createTranslation(text1, sourceLang, targetLang, 'translation_area');
		});

		button2.on('click', function() {
			var tsDropDown = new OO.ui.DropdownInputWidget({
				id: 'tsDropDown',
				options: wikiList
			});

			OO.ui.prompt(
				new OO.ui.HtmlSnippet(tsDropDown.$element.append('<br>')), {
					textInput: {
						placeholder: 'Enter title'
					}
				}).done(function(result) {
				if (result && /\S/.test(result)) {
					const wikiLink = $('#tsDropDown option:selected').val();
					const wikiUrl = wikiLink;
					setCleanSource(result, wikiUrl, 'translation_area');
				}
			});
		});

		container.getElement().append(translation_content_area);
		container.getElement().append(fromLang.$element.css({
			"width": "200",
			"display": "inline-block"
		}));
		container.getElement().append('<span style="color: white">→</span>&nbsp;');
		container.getElement().append(toLang.$element.css({
			"width": "200",
			"display": "inline-block"
		}));
		container.getElement().append(button2.$element.css({
			'float': 'left'
		}));
		container.getElement().append(button1.$element.css({
			'float': 'right'
		}));
	};

	const fillRc = function(array) {
		if (array === null) {
			setRecentChangesFeed(wikiList[0].data, null, "ted_rc_info_container");
		} else {
			var encodedResultVal = encodeHTMLEntities(wikiRcTags[array].label);
			setRecentChangesFeed(wikiList[0].data, wikiRcTags[array].name, wikiRcTags[array].id + "_container");
		}
	};

	const setRcTabs = function() {
		$('#ted_rcinfo').click(function() {
			$('#ted_rc_info_container').html("");
			fillRc(null);
			$('.tab_content3').hide();
			$("ul.tabs3 li.active").removeClass("active");
			$('#ted_rcinfo').parent().addClass("active");
			$('#ted_rc_info_container').show();
		});

		const registerButtonEvent = function(id, array) {
			$('#' + id + '_button').click(function() {
				$('#' + id + '_container').html("");
				fillRc(array);
				$('.tab_content3').hide();
				$("ul.tabs3 li.active").removeClass("active");
				$('#' + id + '_button').parent().addClass("active");
				$('#' + id + '_container').show();
			});
		};
		for (var i = 0; i < wikiRcTags.length; i++) {
			var encodedResultVal = encodeHTMLEntities(wikiRcTags[i].label);
			const id = wikiRcTags[i].id;
			const array = i;
			$("ul.tabs3").append('<li><a href="#" id="' + id + '_button" class="tab_buttons3">' + encodedResultVal + '</a></li>');
			$(".tab_container3").append('<div class="tab_content3" id="' + id + '_container" style="overflow: auto; height: 200px;">' + "" + '</div>');
			registerButtonEvent(id, array);
		}

		fillRc(null);
	};

	const setRecentChangesViewLayout = function() {
		var container = containers.recentChangesView;
		var tabArea = $(`
	<div id="wrapper">
		<ul class="tabs3">
			<li class="active"><a href="#" id="ted_rcinfo" class="tab_buttons3">일반</a></li>
		</ul>
		<div class="tab_container3">
			<div id="ted_rc_info_container" class="tab_content3"  style="overflow: auto; height: 200px;">
			</div>
		</div>
	</div>
`);
		container.getElement().append(tabArea);
	};

	const fillBulletinBoard = function(array) {
		var encodedResultVal = encodeHTMLEntities(wikiBoards[array].label);
		setSections(wikiBoards[array].title, wikiList[0].data, wikiBoards[array].id + "_container");
	};

	const setBulletinBoardTabs = function() {
		const registerButtonEvent = function(id, array) {
			$('#' + id + '_button').click(function() {
				$('#' + id + '_container').html("");
				fillBulletinBoard(array);
				$('.tab_content2').hide();
				$("ul.tabs2 li.active").removeClass("active");
				$('#' + id + '_button').parent().addClass("active");
				$('#' + id + '_container').show();
			});
		};
		for (var i = 0; i < wikiBoards.length; i++) {
			var encodedResultVal = encodeHTMLEntities(wikiBoards[i].label);
			const id = wikiBoards[i].id;
			const array = i;
			$("ul.tabs2").append('<li><a href="#" id="' + id + '_button" class="tab_buttons2">' + encodedResultVal + '</a></li>');
			$(".tab_container2").append('<div class="tab_content2" id="' + id + '_container" style="overflow: auto; height: 90px;">' + "" + '</div>');
			registerButtonEvent(id, array);
		}
	};

	const setBulletinBoardViewLayout = function() {
		var container = containers.bulletinBoardView;
		var tabArea = $(`
	<div id="wrapper">
		<ul class="tabs2">
			<li class="active"><a href="#" id="ted_bulletinboard" class="tab_buttons2">정보</a></li>
		</ul>
		<div class="tab_container2">
			<div id="ted_bulletin_board_container" class="tab_content2">
				<h1>게시판</h1>
				게시판 버튼을 클릭하면 게시글 제목이 표시됩니다. 최근 항목부터 나열합니다.<br/>
			</div>
		</div>
	</div>
`);
		container.getElement().append(tabArea);
	};

	const setPageViewLayout = function() {
		var container = containers.pageView;
		var tabArea = $(`
	<div id="wrapper">
		<ul class="tabs1">
			<li class="active"><a href="#" id="ted_pageinfo" class="tab_buttons1">정보</a></li>
			<li><a href="#" id="ted_pagesandbox" class="tab_buttons1">연습장</a></li>
		</ul>
		<div class="tab_container1">
			<div id="ted_page_info_container" class="tab_content1">
				<h1>문서</h1>
				상단의 '문서 탭에 추가' 버튼을 클릭하면 이 공간에 문서가 추가됩니다.<br>
			</div>
			<div id="ted_page_sandbox_container" class="tab_content1">
				<textarea style="width: 100%; height: 240px;"></textarea>
			</div>
		</div>
	</div>
`);
		container.getElement().append(tabArea);
	};

	const setSearchViewLayout = function() {
		var container = containers.searchView;
		var textInput = new OO.ui.SearchInputWidget({
			value: ''
		}).on('enter', function() {
			var search_str = textInput.getValue();
			var params = {
					action: 'query',
					list: 'search',
					srsearch: search_str,
					format: 'json'
				},
				api = new mw.ForeignApi(dropDown.getValue() + '/w/api.php');

			$('#ted_search_result').html("");

			function prependCreateItem() {
				$('#ted_search_result').prepend($('<option>', {
					value: {
						wiki: findLabelByDataFromWikilist(dropDown.getValue()),
						title: textInput.getValue()
					},
					text: '[' + findLabelByDataFromWikilist(dropDown.getValue()) + '] ' + textInput.getValue()
				}));
			}

			api.get(params).done(function(data) {
				if (data.query.search.length === 0) {
					prependCreateItem();
					return;
				}
				var matched = false;
				$.each(data.query.search, function(i, item) {
					if (item.title === textInput.getValue()) {
						matched = true;
					}
					$('#ted_search_result').append($('<option>', {
						value: {
							wiki: findLabelByDataFromWikilist(dropDown.getValue()),
							title: item.title
						},
						text: '[' + findLabelByDataFromWikilist(dropDown.getValue()) + '] ' + item.title
					}));
				});
				if (!matched) {
					prependCreateItem();
				}

			});
		});

		var dropDown = new OO.ui.DropdownInputWidget({
			id: "dropDownId",
			options: wikiList
		});

		var fieldSet = new OO.ui.FieldsetLayout({
			label: '검색 항목 지정'
		});

		fieldSet.addItems([
			new OO.ui.FieldLayout(dropDown, {
				label: '언어 선택',
				align: 'right'
			}),
			new OO.ui.FieldLayout(textInput, {
				label: '검색어',
				align: 'right'
			})
		]);

		var button1 = new OO.ui.ButtonWidget({
			label: '선택 해제',
			title: '선택 해제'
		});

		var button2 = new OO.ui.ButtonWidget({
			label: '문서 탭에 추가',
			title: '문서 탭에 추가'
		});

		var result = $('<select size="5000" id="ted_search_result"></select>').css({
			"overflow": "auto",
			"width": "calc(100% - 10px)",
			"margin-top": "1em",
			"height": "130px",
			"overflow-y": "auto"
		});

		dropDown.on('change', function() {
			$('#ted_search_result').html("");
		});

		button1.on('click', function() {
			$("#ted_search_result").val([]);
		});

		button2.on('click', function() {
			var resultVal = $("#ted_search_result").find(":selected").text();
			if (resultVal === null || !/\S/.test(resultVal)) {
				return;
			}

			for (var i = 0; i < $(".tab_buttons1").length; i++) {
				var tabButton = $(".tab_buttons1")[i];
				if ($(tabButton).text() === resultVal) {
					$(tabButton).trigger('click');
					return;
				}
			}

			pageTabCnt++;
			const tabCnt = pageTabCnt;
			setEditTabStatus(tabCnt, {});

			var tab_content_area = '<textarea class="ted_edit" style="width: 100%; height: 240px;" id="ted_edit_' + pageTabCnt + '"></textarea><div id="ted_preview_' + pageTabCnt + '" style="width: 100%; min-height: 240px; max-height: 240px; overflow-y: scroll; display: none;"></div><div id="ted_preview2_' + pageTabCnt + '" style="width: 50%; min-height: 240px; max-height: 240px; overflow-y: scroll; display: none;"></div>';
			var encodedResultVal = encodeHTMLEntities(resultVal);
			var currentTitle = resultVal.replace(/^\[\S+\] /, '');
			var currentWikiLabel = resultVal.replace(/^\[(\S+)\] (.+)/, '$1');
			var button3 = new OO.ui.ButtonWidget({
				id: 'ted_submit_' + pageTabCnt,
				label: '게시',
				title: '게시'
			});
			var button4 = new OO.ui.ButtonWidget({
				id: 'ted_interwiki_' + pageTabCnt,
				label: '인터위키 연결',
				title: '인터위키 연결'
			});
			var button5 = new OO.ui.ButtonWidget({
				id: 'ted_prev_edit_toggle_' + pageTabCnt,
				label: '미리 보기',
				title: '미리 보기'
			});
			var button6 = new OO.ui.ButtonWidget({
				id: 'ted_tool_' + pageTabCnt,
				label: '도구',
				title: '도구'
			});
			const wikiUrl = dropDown.getValue();

			$("ul.tabs1").append('<li><a href="#" class="tab_buttons1" id="pageTab' + pageTabCnt + '">' + encodedResultVal + '</a></li>');
			$(".tab_container1").append('<div id="pageTab' + pageTabCnt + '_container" class="tab_content1">' + tab_content_area + '<div class="ted_toolbox"></div></div>');
			$("#pageTab" + pageTabCnt + '_container .ted_toolbox')
				.append(button4.$element.css({
					'float': 'left',
					'margin-top': '0.25em'
				})).append(button3.$element.css({
					'float': 'right',
					'margin-top': '0.25em'
				})).append(button6.$element.css({
					'float': 'left',
					'margin-top': '0.25em'
				})).append(button5.$element.css({
					'float': 'right',
					'margin-top': '0.25em',
					'margin-right': '0.5em'
				}));
			setSource(currentTitle, wikiUrl, 'ted_edit_' + pageTabCnt);

			button3.on('click', function() {
				var title = currentTitle;
				submitPage(title, wikiUrl, $('#ted_edit_' + tabCnt).val());
			});

			button4.on('click', function() {
				var fromTitle = currentTitle;
				var iwWikiList = [];
				const fromSite = findWdNameByLabelFromWikilist(currentWikiLabel);
				for (var i = 0; i < wikiList.length; i++) {
					if (wikiList[i].label === currentWikiLabel) {
						continue;
					}
					iwWikiList.push({
						data: wikiList[i].wdName,
						label: wikiList[i].wdName
					});
				}

				var iwDropDown = new OO.ui.DropdownInputWidget({
					id: 'iwDropDown',
					options: iwWikiList
				});

				OO.ui.prompt(
					new OO.ui.HtmlSnippet(iwDropDown.$element.append('<br>')), {
						textInput: {
							placeholder: 'Enter title'
						}
					}).done(function(result) {
					if (result && /\S/.test(result)) {
						const toSite = $('#iwDropDown option:selected').val();
						const toTitle = result;
						setSitelink(fromSite, fromTitle, toSite, toTitle);
					}
				});
			});

			button5.on('click', function() {
				const title = currentTitle;
				const previewId = '#ted_preview_' + tabCnt;
				const preview2Id = '#ted_preview2_' + tabCnt;
				$(previewId).css("width", "100%");
				$(preview2Id).hide();
				togglePreview(title, wikiUrl, $('#ted_edit_' + tabCnt).val(), tabCnt);
			});

			var messageDialog = new OO.ui.MessageDialog();
			var windowManager = new OO.ui.WindowManager();
			$('#pageTab' + tabCnt + '_container').append(windowManager.$element);
			windowManager.addWindows([messageDialog]);

			button6.on('click', function() {
				var fieldSet = new OO.ui.FieldsetLayout({
					label: '도구를 선택하세요'
				});

				var button6_cleanup_machine_translation = new OO.ui.ButtonWidget({
					label: '기계 번역 정리',
					title: '기계 번역 정리'
				});
				var button6_import = new OO.ui.ButtonWidget({
					label: '위키 문서 정보 가져오기',
					title: '위키 문서 정보 가져오기'
				});

				fieldSet.addItems([button6_cleanup_machine_translation, button6_import]);

				button6_cleanup_machine_translation.on("click", function() {
					const id = '#ted_edit_' + tabCnt;
					const orig = $(id).val().trim();
					const result = replaceStrForTranslation(orig).trim();
					if (orig === result) {
						showMessage("정리할 대상이 없습니다", "기계 번역 정리");
					} else {
						$(id).val(result);
						showMessage("기계 번역 정리가 완료되었습니다", "기계 번역 정리");
					}
					windowManager.closeWindow(messageDialog);
				});

				button6_import.on("click", function() {
					const previewId = '#ted_preview_' + tabCnt;
					const preview2Id = '#ted_preview2_' + tabCnt;
					const editId = '#ted_edit_' + tabCnt;
					const editIdVal = $(editId).val();
					const tabStat = getEditTabStatus(tabCnt);
					if (tabStat.isPreviewMode === false) {
						var title = currentTitle;
						togglePreview(title, wikiUrl, $('#ted_edit_' + tabCnt).val(), tabCnt);
					}
					$(previewId).css("width", "50%");
					$(preview2Id).css('display', 'inline-block').show();
					$(preview2Id).html('');

					const timer = ms => new Promise(res => setTimeout(res, ms));
					async function load() {
						for (var i = 0; i < 20; i++) {
							if (tabStat.isPreviewCompleted === false) {
								await timer(1000);
								continue;
							}
							$(preview2Id).html('<span id="tab_edit_' + tabCnt + '_import_info" style="color: #36c; cursor: pointer;">정보 분석 시작</span><br>')
								.append('<span id="tab_edit_' + tabCnt + '_import_links" style="color: #36c; cursor: pointer;">모든 링크 나열</span><br>')
								.append('<span id="tab_edit_' + tabCnt + '_import_external_links" style="color: #36c; cursor: pointer;">외부 링크 문단 나열</span><br>')
								.append('<span id="tab_edit_' + tabCnt + '_import_categories" style="color: #36c; cursor: pointer;">모든 분류 나열</span>')
								.append('<textarea id="tab_edit_' + tabCnt + '_import_textarea" style="width: 100%; height: 150px;"></textarea>');

							$('#tab_edit_' + tabCnt + '_import_info').on('click', function() {
								const newTabStat = getEditTabStatus(tabCnt);
								if (newTabStat.isAnalyzed) {
									showMessage('이미 정보 분석이 진행되었습니다.', '정보 분석');
									return;
								}
								analyzePage(previewId, wikiUrl, tabCnt);
							});

							$('#tab_edit_' + tabCnt + '_import_links').on('click', function() {
								const newTabStat = getEditTabStatus(tabCnt);
								if (!newTabStat.isAnalyzed) {
									showMessage('"정보 분석" 링크를 먼저 클릭하여 위키 정보를 먼저 분석해 주십시오.', '정보 분석');
									return;
								}
								copyLinks(previewId, tabCnt);
							});

							$('#tab_edit_' + tabCnt + '_import_external_links').on('click', function() {
								copyExtLinks(editIdVal, previewId, tabCnt);
							});

							$('#tab_edit_' + tabCnt + '_import_categories').on('click', function() {
								const newTabStat = getEditTabStatus(tabCnt);
								if (!newTabStat.isAnalyzed) {
									showMessage('"정보 분석" 링크를 먼저 클릭하여 위키 정보를 먼저 분석해 주십시오.', '정보 분석');
									return;
								}
								copyCategories(previewId, tabCnt);
							});

							break;
						}
					}
					load();

					windowManager.closeWindow(messageDialog);
				});

				windowManager.openWindow(messageDialog, {
					title: '도구 선택',
					message: new OO.ui.HtmlSnippet(fieldSet.$element),
					actions: [{
						action: 'accept',
						label: '취소',
						flags: 'primary'
					}]
				});

			});

			$(".tab_content1").hide();
			$("ul.tabs1 li.active").removeClass("active");
			$("#pageTab" + pageTabCnt).parent().addClass("active");
			$("#pageTab" + pageTabCnt + "_container").show();

			$("#pageTab" + pageTabCnt).click(function() {
				$(".tab_content1").hide();
				$("ul.tabs1 li.active").removeClass("active");
				$(this).parent().addClass("active");

				$("#" + $(this).attr("id") + "_container").show();
			});

			$("#pageTab" + pageTabCnt).on("dblclick", function() {
				var parentElemnt = $(this).parent();
				var contentElement = $("#" + $(this).attr("id") + "_container");
				OO.ui.confirm('탭을 닫으시겠습니까?').done(function(confirmed) {
					if (confirmed) {
						contentElement.remove();
						parentElemnt.remove();
						$('#ted_pageinfo').click();
					}
				});
			});

		});

		container.getElement().append(fieldSet.$element.css({
			"width": "calc(100% - 10px)",
			"color": "white"
		}));
		container.getElement().append(result);

		container.getElement().append(button2.$element.css({
			'float': 'right',
			'margin-right': '10px'
		}));

		container.getElement().append(button1.$element.css({
			'float': 'right',
			'margin-right': '5px'
		}));
	};

	const registerComponent = function() {
		const setContainerContent = function(componentName, container) {
			containers[componentName] = container;
		};
		
		for (var i = 0; i < contribComponentTabs.length; i++) {
			const componentName = contribComponentTabs[i].name;
			const componentFunc = contribComponentTabs[i].func;
			glLayout.registerComponent(componentName, function(container, componentState) {
				setContainerContent(componentName, container);
				container.getElement().css('padding', '1em');
				componentFunc();
			});
		}
	};

	const createDashboard = function() {
		const dashboardHeight = 700;
		glLayout = new GoldenLayout(glConfig, $('#tedDashboardArea'));
		$("#tedDashboardArea").css("background-color", "#000000");
		$("#tedDashboardArea").css("height", dashboardHeight + 50);
		registerComponent();
		glLayout.init();
		glLayout.on('stateChanged', () => glLayout.updateSize($('#tedDashboardArea').width() - 30, dashboardHeight));

		$('ul.lm_tabs').css('list-style', 'none');
		$(".lm_header").css("background-color", "#000000");

		setBulletinBoardTabs();
		setRcTabs();
		$("#ted_pageinfo").click(function() {
			$(".tab_content1").hide();
			$("ul.tabs1 li.active").removeClass("active");
			$("#ted_pageinfo").parent().addClass("active");
			$("#ted_page_info_container").show();
		});
		$("#ted_pagesandbox").click(function() {
			$(".tab_content1").hide();
			$("ul.tabs1 li.active").removeClass("active");
			$("#ted_pagesandbox").parent().addClass("active");
			$("#ted_page_sandbox_container").show();
		});

		$("#ted_bulletinboard").click(function() {
			$(".tab_content2").hide();
			$("ul.tabs2 li.active").removeClass("active");
			$("#ted_bulletinboard").parent().addClass("active");
			$("#ted_bulletin_board_container").show();
		});

		$("#ted_pageinfo").click();
	};

	$.when(mw.loader.using('mediawiki.util'), $.ready).then(function() {
		var newElement = mw.util.addPortletLink(
			'p-tb',
			'/wiki/Special:TedDashboard',
			'★ 테드 대시보드',
			't-mworg',
			'테드 대시보드로 이동합니다',
			'',
			'#t-specialpages'
		);
	});
	if (mw.config.get('wgNamespaceNumber') == -1 && (mw.config.get('wgTitle') == "TedDashboard")) {
		initDashboard();
	}

}());
/* </nowiki> */