').appendTo($dimmed);\n this.options.click && this.$backdrop.one('click', $.proxy(this.hide, this));\n\n return this.$backdrop;\n },\n toggle: function() {\n this.$pane.modal(this.isShown ? 'hide' : 'show');\n },\n show: function() {\n if (this.options.backdrop && !this.isShown) {\n this.backdrop();\n }\n\n this.$pane\n .addClass('modal')\n .attr('tabindex', -1)\n .appendTo($dimmed)\n .show()\n .css({\n marginTop: Math.floor(-this.$pane.outerHeight() / 2),\n marginLeft: Math.floor(-this.$pane.outerWidth() / 2),\n })\n .addClass('in');\n\n this.$backdrop && this.$backdrop.addClass('in');\n this.esc();\n !this.options.scroll && this.setBodyOverflow('hidden');\n\n this.isShown = !0;\n },\n hide: function() {\n this.$pane.trigger($.Event('hide.modal'));\n\n this.$pane.removeClass('in').hide();\n this.$backdrop && this.removeBackdrop();\n this.esc();\n !this.options.scroll && this.setBodyOverflow();\n\n this.isShown = !1;\n },\n removeBackdrop: function() {\n this.$backdrop.remove();\n this.$backdrop = null;\n },\n esc: function() {\n if (!this.options.keyboard) {\n return;\n }\n\n if (!this.isShown) {\n $body.bind(\n 'keyup.modal',\n $.proxy(function(e) {\n e.which === 27 && this.hide();\n }, this),\n );\n } else {\n $body.unbind('keyup.modal');\n }\n },\n setBodyOverflow: function(css) {\n css && (this.cacheBodyCssOverflow = $body.css('overflow'));\n $body.css('overflow', css || this.cacheBodyCssOverflow);\n },\n };\n\n /*\n * Get global modal options\n */\n typeof exports['___modalConf'] === 'object' && $.extend(!0, defaults, exports['___modalConf']);\n\n /*\n * Modal plugin definition\n */\n $.fn.modal = function(options) {\n return this.each(function() {\n var $this = $(this),\n data = $this.data('modal');\n\n !data && $this.data('modal', (data = new Modal($this, options)));\n\n typeof options === 'string'\n ? data[options]()\n : (!options || (options && !options.remote)) && data.show();\n /*\n\t options && options.remote // 원격일 경우\n\t options && !options.remote // 클릭해서 띄울 경우\n\t !options // 생성한 경우\n */\n });\n };\n\n /*\n * Set body overflow\n */\n function setBodyOverflow(css) {\n $body.css('overflow', css);\n }\n\n /*\n * Modal data-api definition\n */\n $body.on('click', '[data-ui=\"modal\"]', function(e) {\n var $this = $(this),\n href = $this.attr('href'),\n isRemote = !/^#/.test(href),\n $target = $(!isRemote ? href : '
'),\n options = $.extend(isRemote ? { remote: href } : {}, $this.data());\n\n $target.modal(options).one('hide.modal', function() {\n $this.focus();\n });\n\n e.preventDefault();\n });\n // $hash.length && $hash.hasClass( 'modal' ) && $hash.modal();\n})(window, jQuery);\n","var isApp;\nvar isRc = '';\nvar isMobile;\n\nfunction init() {\n isApp = window.npConf && window.npConf.isApp == 'true';\n isRc = /(rc.)/i.test(location.href) ? 'rc.' : '';\n\n isMobile = /(android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini|NC Noob)/i.test(\n navigator.userAgent.toLowerCase(),\n );\n}\n\n//링크 주소 펙토리-------------------------------------------------------------------------------------------\nfunction factory(_obj) {\n /*\n * 대상 알림코드 : 1000XXXXXX (뒷자리 6자를 제외하면 1000 이 되는 모든 알림 코드입니다. 1000001001, 1000001002, 1000002001, ......)\n *\t안내 메시지 : 퍼플에서 확인해 주세요.\n * */\n var notiCode = _obj.notiCode.toString();\n var isPurpleNotiCode = notiCode.substr(0, 4) === '1000';\n\n var link = '';\n var thisSite = '';\n if (window.npConf) {\n thisSite = npConf.site;\n }\n if (jQuery('#nc-cnb').length > 0 && window.userData) {\n thisSite = userData.site;\n }\n\n if (_obj.msgLink) {\n var thisDeviceLink;\n if (isApp) {\n thisDeviceLink = _obj.msgLink.mobileApp || _obj.msgLink.mobile;\n } else if (isMobile) {\n thisDeviceLink = _obj.msgLink.mobile;\n } else {\n thisDeviceLink = _obj.msgLink.web;\n }\n\n if (!!thisDeviceLink) {\n // 앱일경우 캐릭터 정보를 붙여서 보낸다\n if (isApp) {\n thisDeviceLink = addParam(\n thisDeviceLink,\n 'characterName',\n encodeURI(_obj.subscriber.characterName) || '',\n );\n thisDeviceLink = addParam(thisDeviceLink, 'serverId', _obj.subscriber.serverID || '');\n }\n\n // 주소에 redirect 문자열이 있을 경우 site=bns 형식의 파람을 붙인다\n if (thisDeviceLink.indexOf('redirect') > 0) {\n thisDeviceLink = addParam(thisDeviceLink, 'site', thisSite);\n }\n\n // 친구 수락 예외 처리\n if (\n String(_obj.notiCode).substring(0, 5) == '23002' ||\n String(_obj.notiCode).substring(0, 5) == '23001' ||\n String(_obj.notiCode).substring(0, 5) == '23003'\n ) {\n var arr = thisDeviceLink.split('?');\n if (arr[1]) {\n thisDeviceLink = arr[0] + '/' + thisSite + '/timeline/wall?' + arr[1];\n }\n }\n\n link = 'href=\"' + thisDeviceLink + '\"';\n } else {\n var txt = notiL10NData.availableCheck(\n _obj.msgLink.ingame,\n _obj.msgLink.mobileApp,\n _obj.msgLink.mobile,\n _obj.msgLink.web,\n );\n link = 'onclick=\"alert(' + txt + ');\"';\n if (!_obj.msgLink.ingame && !_obj.msgLink.mobileApp && !_obj.msgLink.mobile && !_obj.msgLink.web)\n link = '';\n }\n }\n\n if (isPurpleNotiCode) {\n var msg = notiL10NData.AvailablePurple;\n link = 'onclick=\"window.cnb.message(\\'' + msg + '\\')\"';\n }\n\n return link;\n}\n\nfunction addParam(_link, _name, _value) {\n var connect = _link.indexOf('?') == -1 ? '?' : '&';\n return _link + connect + _name + '=' + _value;\n}\n\nfunction replaceURL(_url) {\n if (!window.isTestServer || !isTestServer()) return _url;\n return 'http://' + isRc + 'tg.' + _url.substr(_url.indexOf('sandbox.plaync.com'));\n}\n\n//초기 실행 -------------------------------------------------------------------------------------------\njQuery(function() {\n init();\n});\n\nconst _link = {\n factory: factory,\n};\n\nexport default _link;\n","var isRc = /(rc.)/i.test(location.href) ? 'rc.' : '';\nvar isHttps = location.protocol == 'https:' && location.href.indexOf('https:') > -1;\nvar api = {};\n\nfunction init() {\n var path = 'https://wstatic-cdn.plaync.com';\n if (!isHttps) {\n path = 'http://static.plaync.co.kr';\n }\n api = {\n staticUrl: path + '/resource/noti/icon/',\n aionFile: 'http://' + isRc + 'gamepic.plaync.com/images/0301/',\n };\n}\n\nfunction aionChar(_serverId, _charId) {\n if (isHttps || typeof _serverId == 'undefined' || typeof _charId == 'undefined') {\n return api.staticUrl + 'aionprofile.jpg';\n } else {\n var char4 = _charId.substring(_charId.length - 4);\n return api.aionFile + _serverId + '/' + char4 + '/' + _charId + '.jpg';\n }\n}\n\nfunction factory(_obj) {\n var img;\n\n if (_obj.msgType == 2) {\n if (_obj.publisher.gameID == '3') {\n img = aionChar(_obj.publisher.serverID, _obj.publisher.characterID); // 친구신청 / 아이온\n } else if (_obj.publisher.gameID == '4') {\n img = api.staticUrl + 'l1profile.gif'; // 친구신청 / L1\n } else if (_obj.publisher.gameID == '5') {\n img = api.staticUrl + 'l2profile.gif'; // 친구신청 / L2\n } else {\n img = _obj.thumbnailUrl; // 친구신청 / 통합계정\n }\n } else {\n img = _obj.thumbnailUrl;\n }\n\n return img;\n}\n\ninit();\n\nconst _thumb = {\n factory: factory,\n};\n\nexport default _thumb;\n","import _link from './notiLink';\nimport _thumb from './notiThumbnail';\n\nfunction tmpMsg(_obj) {\n var link = _link.factory(_obj);\n\n var itemNode = $(document.createElement('li'));\n if (_obj.isNew) itemNode.addClass('on');\n itemNode.data(_obj);\n\n var iconUrl = _thumb.factory(_obj);\n var iconCls = /noti\\/icon/gi.test(iconUrl) ? ' class=\"icon\"' : '';\n\n var tmpl =\n '
';\n\n if (_obj.msgType == 2) {\n // 친구 신청일 경우 버튼 추가\n tmpl +=\n '
' +\n ' ' +\n '' +\n '
';\n }\n\n itemNode.append(tmpl);\n return itemNode;\n}\n\nfunction tmpLoading(msg) {\n return '
Loading...
';\n}\n\nfunction tmpNoMsg(msg) {\n return '
';\n}\n\nfunction tmpOkFriend(_obj) {\n var tmpl =\n '
' +\n '
친구가 되었습니다.
';\n return tmpl;\n}\n\nfunction friendAgree_M(_nick) {\n var tmpl =\n '
' +\n '
' +\n '' +\n '' +\n '
' +\n '- NC친구가 되면?
' +\n '- 서로의 B&S, 아이온 캐릭터를 조회할 수 있습니다.
(단, 닉네임님이 비공개한 캐릭터는 조회 불가) ' +\n '
' +\n '
' +\n _nick +\n '님의 NC친구 신청을
수락하시겠습니까?
' +\n '
' +\n '' +\n '' +\n '' +\n '
' +\n '' +\n '
';\n return tmpl;\n}\n\nfunction friendAgree_I(_nick) {\n var tmpl =\n '
' +\n '
' +\n '' +\n '' +\n '' +\n _nick +\n '님의 친구 신청을 수락합니다.
' +\n '' +\n '- 친구가 되면?
' +\n '- 서로의 아이온 캐릭터를 조회할 수 있습니다.
' +\n '- 리니지/리니지2의 경우 신청/수락한 캐릭터만 조회할 수 있습니다.
' +\n '
' +\n '' +\n '' +\n '' +\n '' +\n '
' +\n '' +\n '
';\n return tmpl;\n}\n\nfunction alertMessage(msg) {\n var tmpl =\n '
' +\n '
' +\n '' +\n '
' +\n msg +\n '
' +\n '
' +\n '' +\n '' +\n '
' +\n '' +\n '
';\n return tmpl;\n}\n\nvar currentTime;\n\nfunction makeTime(_createMillisec) {\n var createTime = parseInt(_createMillisec);\n var createTime2 = new Date(createTime);\n var howTime = parseInt((currentTime - createTime) / 1000);\n var timeElm;\n\n if (howTime < 60) {\n timeElm = notiL10NData.AfewsecondsAgo;\n } else if (howTime >= 60 && howTime < 3600) {\n timeElm = parseInt(howTime / 60) + notiL10NData.MinutesAgo;\n } else if (howTime >= 3600 && howTime < 86400) {\n timeElm = parseInt(howTime / (60 * 60)) + notiL10NData.HhoursAgo;\n } else if (howTime >= 86400 && howTime < 604800) {\n timeElm = parseInt(howTime / (60 * 60 * 24)) + notiL10NData.DaysAgo;\n } else if (howTime >= 604800) {\n timeElm = createTime2.getFullYear() + '.' + (createTime2.getMonth() + 1) + '.' + createTime2.getDate();\n }\n return timeElm;\n}\n\nfunction setCurrentTime(_t) {\n currentTime = _t;\n}\n\nconst tmpl = {\n tmpMsg: tmpMsg,\n tmpLoading: tmpLoading,\n tmpNoMsg: tmpNoMsg,\n tmpOkFriend: tmpOkFriend,\n setCurrentTime: setCurrentTime,\n friendAgree_M: friendAgree_M,\n friendAgree_I: friendAgree_I,\n alertMessage: alertMessage,\n};\n\nexport default tmpl;\n","let isRc = location.href.match(/(rc\\.|rc\\-|rc2\\-)/i) ? location.href.match(/(rc\\.|rc\\-|rc2\\-)/i)[1] : '';\nisRc = (isRc == 'rc2-') ? 'rc-' : isRc;\nif(location.href.match(/(op\\-|opdev\\-)/i)) isRc = 'opdev-';\nlet nowDomain = /(asia\\.nc\\.com)/i.test(location.href) ? 'asia.nc.com' : 'noti.plaync.com';\nlet api = {\n count: location.protocol + '//' + isRc + nowDomain + '/noti/api/common/count.jsonp', //알림카운트\n list: location.protocol + '//' + isRc + nowDomain + '/noti/api/common/list.jsonp', //노티리스트\n confirm: location.protocol + '//' + isRc + nowDomain + '/noti/api/common/confirm.jsonp', //노티읽음 확인\n};\n\nif (/local\\.|localhost|ui-static\\.|file:/i.test(location.href)) {\n api = {\n count: 'http://ui-static.korea.ncsoft.corp/uikit/cnb/data/noticountdummydata.json',\n list: 'http://ui-static.korea.ncsoft.corp/uikit/cnb/data/notilistdummydata.json',\n confirm: '',\n };\n}\nexport default api;\n\n\n","import tmpl from './notiTemplate';\nimport api from './notiApi';\n\nvar isLoading = false;\nvar isFirst = true;\nvar pageNum = 0;\nvar pageTotal = 1;\nvar pageSize = 100;\nvar container = {};\nvar userDataLocale = 'ko-KR';\nvar loadingBar;\n\nvar $dispatcher = jQuery({ name: 'dispatcher' });\n\nfunction init() {\n userDataLocale = window.userData && window.userData.locale ? window.userData.locale : 'ko-KR';\n jQuery('#notiList').append(jQuery(document.createElement('ul')));\n container = jQuery('#notiList ul');\n loadingBar = jQuery(tmpl.tmpLoading()).insertAfter(jQuery('#notiList .loading'));\n\n //알림 읽음 확인 -------------------------------------------------------------------------------------------\n jQuery('#notiList ul .wrapNotice')\n .off('click')\n .on('click', function(event) {\n var notiId = jQuery(this).data('notiid');\n if (jQuery(this).data('isnew')) {\n jQuery.ajax({\n url: api.confirm,\n dataType: 'jsonp',\n type: 'GET',\n data: { notiID: notiId },\n success: function() {},\n beforeSend: function() {},\n complete: function() {},\n error: function() {},\n });\n }\n });\n}\n\n//알림리스트 로딩-------------------------------------------------------------------------------------------\nfunction notiListLoadStart() {\n if (isLoading) return;\n loadingBar.text(notiL10NData.Loading);\n pageNum++;\n\n const apiData = window.notiDummyData || api;\n var request = jQuery.ajax({\n url: apiData.list,\n dataType: 'jsonp',\n type: 'GET',\n jsonpCallback: 'callback',\n // url : 'http://static.plaync.co.kr/gnb/error/gnbNtError.js',\tdataType : \"jsonp\", type : \"GET\", jsonpCallback: \"callback\",\n data: {\n targetCategory: 'GNB_NOTI',\n pageSize: pageSize,\n pageNo: pageNum,\n language: userDataLocale,\n https: window.location.protocol === 'https:',\n },\n beforeSend: function() {\n isLoading = true;\n loadingBar.show();\n },\n complete: function(jqXHR, textStatus) {\n isLoading = false;\n loadingBar.hide();\n\n $dispatcher.trigger('load-complete');\n },\n });\n\n request.done(listLoadComplete);\n request.fail(function(jqXHR, textStatus) {\n isLoading = false;\n loadingBar.hide();\n container.append(tmpl.tmpNoMsg(notiL10NData.ErrorOccurred));\n });\n}\n\nfunction listLoadComplete(_data) {\n var returnCode = parseInt(_data.result.returnCode, 10);\n if (returnCode === 0) {\n var totalCount = parseInt(_data.result.notiResult.totalCount, 10);\n if (totalCount <= 0) {\n pageTotal = 0;\n pageNum = 0;\n jQuery('.wrapNoticeBox').remove();\n container.after(tmpl.tmpNoMsg(notiL10NData.NoNewNotifications));\n } else {\n if (isFirst) {\n pageTotal = Math.floor(totalCount / pageSize) + 1;\n isFirst = false;\n }\n\n tmpl.setCurrentTime(_data.result.notiResult.serverMillisec);\n\n var newList;\n for (var i = 0, j = _data.result.notiResult.notiList.length; i < j; i++) {\n newList = tmpl.tmpMsg(_data.result.notiResult.notiList[i]);\n container.append(newList);\n imgError(newList, _data.result.notiResult.notiList[i]);\n }\n }\n } else {\n var msg;\n if (_data.result.returnCode === '401') {\n msg = notiL10NData.LoginRequired;\n } else if (_data.result.returnCode === '999') {\n msg = notiL10NData.Maintenance;\n } else {\n msg = notiL10NData.ErrorOccurred;\n }\n container.append(tmpl.tmpNoMsg(msg));\n }\n}\n\nfunction imgError(_cont, _obj) {\n var imgs = jQuery(_cont).find('.thumb img');\n if (imgs.length < 1) return;\n\n // 한번만 에러 이벤트 실행 (onErrorUrl 이미지도 없을 경우 무한루프돔!!)\n jQuery(imgs).one('error', function() {\n jQuery(this).attr('src', _obj.onErrorUrl);\n jQuery(this).attr('alt', '');\n });\n}\n\nfunction listLoadError(_data) {\n setTimeout(function() {\n container.empty();\n container.append(tmpl.tmpNoMsg(notiL10NData.Maintenance));\n }, 100);\n}\n\nvar isFirstInit = true;\nwindow.gnbNtError = listLoadError;\n\nwindow.cnbNotiApi = api;\nwindow.ncNotice = {\n $dispatcher,\n start() {\n if (isFirstInit || !jQuery('#notiList ul').length) {\n init();\n isFirstInit = false;\n }\n isFirst = true;\n pageTotal = 0;\n pageNum = 0;\n container.empty();\n notiListLoadStart();\n },\n};\n","import tmpl from './notiTemplate';\n\nvar api = {},\n isRc = '',\n isApp = false,\n isLoading = false,\n container = {},\n nowNode = {},\n puid = '',\n prid = '';\n\nfunction init() {\n isRc = /(rc.)/i.test(location.href) ? 'rc.' : '';\n isApp = window.npConf && window.npConf.isApp == 'true';\n\n var nowDomain = /(asia\\.nc\\.com)/i.test(location.href) ? 'asia.nc.com' : 'noti.plaync.com';\n\n api = {\n deleteNoti: 'http://' + isRc + nowDomain + '/noti/api/common/delete.jsonp', //알림삭제\n accept: 'http://' + isRc + 'sandbox.plaync.com/$!/my/friend/propose/accept.jsonp', //친구수락\n FriendAgree: 'http://' + isRc + 'sandbox.plaync.com/$!/my/profile/updateAgreeFriendAccept.jsonp', //약관동의\n hide: function(_puid, _prid) {\n //친구신청숨기기\n var prefix = 'http://' + isRc + 'sandbox.plaync.com';\n return prefix + '/$!/bns/friend/' + _puid + '/' + _prid + '/propose/hide.jsonp';\n },\n };\n\n container = jQuery('#notiList ul');\n\n //수락 버튼 클릭\n jQuery('#nc-cnb').on('click', '#notiList .wrapButton .btAllow', function(e) {\n // console.log(nowNode, this);\n nowNode = jQuery(this)\n .parents('li')\n .eq(0);\n puid = jQuery(nowNode).data().publisher.id;\n prid = jQuery(nowNode).data().proposalId;\n\n friendAccept();\n });\n\n //숨기기 버튼 클릭\n jQuery('#nc-cnb').on('click', '#notiList .wrapButton .btHidden', function(e) {\n nowNode = jQuery(this)\n .parents('li')\n .eq(0);\n puid = jQuery(nowNode).data().publisher.id;\n prid = jQuery(nowNode).data().proposalId;\n\n jQuery.ajax({\n url: api.hide(puid, prid),\n dataType: 'jsonp',\n type: 'GET',\n data: '',\n success: function(_data) {\n jQuery(nowNode).hide();\n if (_data.result == 'SUCCESS') {\n } else {\n }\n },\n error: function() {\n alertOrModal(notiL10NData.ErrorOccurred); //알림 삭제 실패\n },\n beforeSend: function() {},\n complete: function() {},\n });\n\n jQuery.ajax({\n url: api.deleteNoti,\n dataType: 'jsonp',\n type: 'GET',\n data: { notiID: jQuery(nowNode).data().id, targetCategory: 'GNB_NOTI' },\n success: function(_data) {\n jQuery(nowNode).hide();\n if (_data.result.returnMessage == 'SUCCESS') {\n } else {\n }\n },\n error: function() {\n alertOrModal(notiL10NData.ErrorOccurred); //알림 삭제 실패\n },\n beforeSend: function() {},\n complete: function() {},\n });\n });\n}\n\n//친구수락 요청\nfunction friendAccept() {\n if (isLoading) return;\n jQuery.ajax({\n url: api.accept,\n data: { friendId: puid, proposalId: prid },\n dataType: 'jsonp',\n type: 'GET',\n success: friendAcceptComp,\n beforeSend: function() {\n isLoading = true;\n },\n complete: function() {\n isLoading = false;\n },\n error: function() {},\n });\n}\n\n//서버응답\nfunction friendAcceptComp(_data) {\n if (_data.result == 'SUCCESS' || _data.result == '4006') {\n jQuery(nowNode).empty();\n\n var okmsg = tmpl.tmpOkFriend(jQuery(nowNode).data());\n jQuery(nowNode).append(okmsg);\n alert(notiL10NData.FriendRequest);\n } else if (_data.result == 'NO_AGREEMENT_FRIEND_ACCEPT') {\n friendAgreePop();\n } else if (_data.result == '4015' || _data.result == '4016') {\n alertOrModal(notiL10NData.UnableAddFriends);\n } else if (_data.result == '4000') {\n alertOrModal(notiL10NData.InformationNotAvailable);\n } else {\n alertOrModal(notiL10NData.ErrorOccurred); //친구 수락 실패\n }\n}\n\n//NC 친구 사용 동의 팝업\nfunction friendAgreePop(_testNick) {\n var nick = !_testNick ? jQuery(nowNode).data().publisher.nickname : _testNick;\n\n if (jQuery('#friendAgree_M').length) {\n jQuery($('#friendAgree_M')).modal({ click: false, keyboard: false });\n } else {\n $(tmpl.friendAgree_M(nick)).modal({ click: false, keyboard: false });\n }\n\n //팝업: 동의\n $('#friendAgree_M').on('click', '.yes', function(e) {\n $('#friendAgree_M').modal('hide');\n $('body').css('overflow', 'auto');\n jQuery.ajax({ url: api.FriendAgree, success: friendAgreeComp, dataType: 'jsonp', type: 'GET' });\n });\n\n //팝업: 거부\n $('#friendAgree_M').on('click', '.no', function(e) {\n $('#friendAgree_M').modal('hide');\n $('body').css('overflow', 'auto');\n });\n\n //팝업: 닫기\n $('#friendAgree_M').on('click', '.js_close', function(e) {\n $('#friendAgree_M').modal('hide');\n $('body').css('overflow', 'auto');\n });\n\n //메신저 설치하기\n $('#friendAgree_M').on('click', '.btnNcMsn', function(e) {\n if (isApp) {\n location.href = 'ncm://message?guid=' + puid;\n } else {\n AppLink.excute('ncm://message?guid=' + puid, $(nowNode).data().publisher.nickname);\n }\n });\n}\n\n//팝업 동의 서버 응답\nfunction friendAgreeComp(_data) {\n if (_data.result == 'SUCCESS') {\n setTimeout(function() {\n friendAccept();\n }, 150);\n } else {\n alertOrModal(notiL10NData.ErrorOccurred); //'친구 동의 실패'\n }\n}\n\nfunction alertOrModal(_msg) {\n alert(_msg);\n}\n\n//초기 실행 -------------------------------------------------------------------------------------------\n$(function() {\n if ($('.noticeList, #notiList').length < 1) return;\n init();\n});\n\nconst notiFriends = {\n friendAgreePop: friendAgreePop,\n};\n\nexport default notiFriends;\n","function setTrace(depth) {\n try {\n _trk_clickTrace('EVT', depth);\n } catch (_e) {}\n}\n\nfunction trim(_str) {\n return _str.replace(/^\\s+/, '').replace(/\\s+$/, '');\n}\n\nfunction cutStrByIndex(_str, _cutStringIndex, _cutAddStr = '...') {\n let tempStr = _str;\n if (_str.length > _cutStringIndex) tempStr = _str.substr(0, _cutStringIndex) + _cutAddStr;\n return tempStr;\n}\n\nfunction reEscape(_str) {\n return _str\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n}\n\nconst nowBrowser = (() => {\n let agt = navigator.userAgent.toLowerCase();\n let trident = agt.match(/trident\\/(\\d.\\d)/i);\n\n if (trident !== null) {\n if (trident[1] === '7.0') return 'IE' + 11;\n if (trident[1] === '6.0') return 'IE' + 10;\n if (trident[1] === '5.0') return 'IE' + 9;\n if (trident[1] === '4.0') return 'IE' + 8;\n }\n\n if (navigator.appName === 'Microsoft Internet Explorer') return 'IE' + 7;\n\n if (agt.indexOf('edge') !== -1) return 'Edge';\n if (agt.indexOf('chrome') !== -1) return 'Chrome';\n if (agt.indexOf('opera') !== -1) return 'Opera';\n if (agt.indexOf('staroffice') !== -1) return 'Star Office';\n if (agt.indexOf('webtv') !== -1) return 'WebTV';\n if (agt.indexOf('beonex') !== -1) return 'Beonex';\n if (agt.indexOf('chimera') !== -1) return 'Chimera';\n if (agt.indexOf('netpositive') !== -1) return 'NetPositive';\n if (agt.indexOf('phoenix') !== -1) return 'Phoenix';\n if (agt.indexOf('firefox') !== -1) return 'Firefox';\n if (agt.indexOf('safari') !== -1) {\n return agt.match('crios') ? 'Chrome' : 'Safari';\n }\n if (agt.indexOf('skipstone') !== -1) return 'SkipStone';\n if (agt.indexOf('netscape') !== -1) return 'Netscape';\n if (agt.indexOf('mozilla/5.0') !== -1) return 'Mozilla';\n})();\n\nconst isMobile = /(android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini|NC Noob)/i.test(\n navigator.userAgent.toLowerCase(),\n);\n\nconst isiPhoneX = (function() {\n // Really basic check for the ios platform\n // https://stackoverflow.com/questions/9038625/detect-if-device-is-ios\n const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;\n\n // Get the device pixel ratio\n const ratio = window.devicePixelRatio || 1;\n\n // Define the users device screen dimensions\n const screen = {\n width: window.screen.width * ratio,\n height: window.screen.height * ratio,\n };\n\n // iPhone X Detection\n return iOS && screen.width === 1125 && screen.height === 2436;\n})();\n\nconst isVideoSupport = nowBrowser != 'IE7' && nowBrowser != 'IE8' && !isMobile;\n\nconst movExt = nowBrowser == 'Chrome' ? '.webm' : '.mp4';\n\nconst vendor = (() => {\n const vendors = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'];\n\n for (let i = 0, max = vendors.length; i < max; i++) {\n if (vendors[i] in document.createElement('div').style) {\n return vendors[i].substr(0, vendors[i].length - 9);\n }\n }\n return false;\n})();\n\nfunction prefixStyle(style) {\n if (vendor === false) return false;\n if (vendor === '') return style;\n\n return vendor + style.charAt(0).toUpperCase() + style.substr(1);\n}\n\nfunction getRandomInt(min, max) {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n}\n\n// object to css\n/*const uppercasePattern = /[A-Z]/g;\nconst msPattern = /^ms-/;\nconst cache = {};\n\nfunction hyphenateStyleName(string) {\n return string in cache\n ? cache[string]\n : cache[string] = string\n .replace(uppercasePattern, '-$&')\n .toLowerCase()\n .replace(msPattern, '-ms-');\n}\n\nconst IS_UNITLESS = {\n animationIterationCount: true,\n boxFlex: true,\n boxFlexGroup: true,\n boxOrdinalGroup: true,\n columnCount: true,\n flex: true,\n flexGrow: true,\n flexPositive: true,\n flexShrink: true,\n flexNegative: true,\n flexOrder: true,\n gridRow: true,\n gridColumn: true,\n fontWeight: true,\n lineClamp: true,\n lineHeight: true,\n opacity: true,\n order: true,\n orphans: true,\n tabSize: true,\n widows: true,\n zIndex: true,\n zoom: true,\n\n // SVG-related properties\n fillOpacity: true,\n stopOpacity: true,\n strokeDashoffset: true,\n strokeOpacity: true,\n strokeWidth: true\n};\n\nfunction addPx(name, value) {\n if(typeof value === 'number' && !IS_UNITLESS[ name ]) {\n return value + 'px';\n } else {\n return value;\n }\n}\n\nfunction createMarkup(obj) {\n let keys = Object.keys(obj);\n if (!keys.length) return '';\n let i, len = keys.length;\n let result = '';\n for (i = 0; i < len; i++) {\n let key = keys[i];\n let val = obj[key];\n result += hyphenateStyleName(key) + ':' + addPx(key, val) + ';'\n }\n return result;\n}*/\n\n// jquery plugin\njQuery.fn.extend({\n animateCss: function(animationName, callback) {\n var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';\n this.addClass('animated ' + animationName).one(animationEnd, function() {\n jQuery(this).removeClass('animated ' + animationName);\n if (callback) {\n callback();\n }\n });\n return this;\n },\n});\n\nexport {\n movExt,\n setTrace,\n trim,\n cutStrByIndex,\n nowBrowser,\n isiPhoneX,\n isVideoSupport,\n isMobile,\n vendor,\n prefixStyle,\n reEscape,\n getRandomInt,\n};\n","import { getRandomInt } from '../common/util';\nimport isEmpty from 'lodash/isEmpty';\nimport merge from 'lodash/merge';\nimport keys from 'lodash/keys';\nimport isObject from 'lodash/isObject';\n// import hexToRgba from 'hex-to-rgba';\n\n/*import jss from 'jss';\nimport preset from 'jss-preset-default';\njss.setup(preset());*/\n\nclass Theme {\n constructor() {\n // this.__jss = new Jss('theme-' + getRandomInt(0, 9));\n this.__jss = new Jss('custom-theme');\n }\n\n update(config) {\n const biImg = config.bi.image || {};\n const header = config.header || {};\n\n let topBi = biImg.medium || biImg.top || biImg,\n lnbBi = biImg.lnb || biImg;\n\n const mobileBIStyle = this.getBIStyle(lnbBi);\n const mainBIStyle = this.getBIStyle(topBi, false);\n const subBIStyle = this.getBIStyle(lnbBi);\n // const stickyBIStyle = this.getBIStyle(lnbBi, false);\n\n const isWhiteTheme = config.type === 'C' || config.type === 'D';\n this.__style = {\n theme: {\n 'nc-cnb .ncc-gnb-wrap .ncc-bi': mobileBIStyle,\n // 'nc-cnb.is-sticky .ncc-gnb-wrap .ncc-bi': stickyBIStyle,\n 'nc-cnb .ncc-lnb-header-bi .ncc-bi': subBIStyle,\n 'nc-cnb .ncc-header': isWhiteTheme ? {} : { backgroundColor: header.medium || {} },\n 'nc-cnb.is-sticky .ncc-header': isWhiteTheme ? {} : { backgroundColor: header.mediumSticky || {} },\n 'nc-cnb .ncc-left-panel-header': isWhiteTheme ? {} : { backgroundColor: header.lnb || {} },\n },\n // subBi: subBIStyle,\n '@media (min-width: 960px)': {\n theme: {\n 'nc-cnb .ncc-gnb-wrap .ncc-bi': mainBIStyle,\n 'nc-cnb .ncc-header': isWhiteTheme ? {} : { backgroundColor: header.large || {} },\n },\n },\n };\n\n // lnb dropdown 셋팅\n if (!isEmpty(config.lnbDropdown)) {\n const { itemColor, itemBorderColor, itemHoverColor } = config.lnbDropdown;\n\n const dropdownTheme = {\n theme: {\n // 'nc-cnb.is-sticky .ncc-dropdown .dropdown-toggle': { backgroundColor: itemHoverColor },\n 'nc-cnb .ncc-dropdown .dropdown-item': {\n backgroundColor: itemColor,\n borderColor: itemBorderColor,\n },\n 'nc-cnb .ncc-header .ncc-dropdown .dropdown-item:hover': {\n backgroundColor: itemHoverColor,\n borderColor: itemHoverColor,\n },\n 'nc-cnb .ncc-left-panel .ncc-dropdown .dropdown-toggle': { backgroundColor: itemHoverColor },\n },\n };\n\n this.__style = merge(this.__style, dropdownTheme);\n }\n\n // theme 셋팅\n if (typeof config.theme !== 'undefined') {\n let customTheme = { theme: {} };\n\n // set colors\n const colorScheme = config.theme.colorScheme;\n if (isObject(colorScheme)) {\n if (colorScheme.default) {\n customTheme.theme['nc-cnb.is-sticky .ncc-header'] = customTheme.theme[\n 'nc-cnb .ncc-left-panel-header'\n ] = customTheme.theme['nc-cnb .ncc-profile-img.ic-home::after'] = customTheme.theme[\n 'nc-cnb .ncc-shortcut'\n ] = customTheme.theme['nc-cnb .ncc-userinfo:after'] = {\n backgroundColor: colorScheme.default,\n };\n }\n if (colorScheme.defaultOn) {\n customTheme.theme['nc-cnb .ncc-shortcut-item__link:hover'] = customTheme.theme[\n 'nc-cnb .ncc-profile-img.ic-home:hover::after'\n ] = {\n backgroundColor: colorScheme.defaultOn,\n };\n }\n if (colorScheme.start) {\n customTheme.theme['nc-cnb .ncc-gamestart-btn__start::before'] = {\n backgroundColor: colorScheme.start,\n };\n }\n if (colorScheme.startOn) {\n customTheme.theme['nc-cnb .ncc-gamestart-btn__start:hover::before'] = {\n backgroundColor: colorScheme.startOn,\n };\n }\n if (isObject(colorScheme.subMenu)) {\n const { hover, bar, barImg } = colorScheme.subMenu;\n if (!isEmpty(hover)) {\n customTheme.theme['nc-cnb .ncc-lnb .ncc-lnb-item__sub li.is-active > a'] = { color: hover };\n customTheme.theme['nc-cnb .ncc-depth2-list-wrap .ncc-depth2-list-items.selected a'] = {\n color: hover,\n };\n }\n\n if (!isEmpty(bar)) {\n if (!isEmpty(barImg)) {\n let img = `url(${barImg}) no-repeat center 0`;\n customTheme.theme['nc-cnb .ncc-lnb .ncc-lnb-hover'] = { background: img };\n } else {\n let gradient = `linear-gradient(to left, rgba(0,0,0,0), ${bar}, white, ${bar}, rgba(0,0,0,0))`;\n customTheme.theme['nc-cnb .ncc-lnb .ncc-lnb-hover'] = { background: gradient };\n\n let selectedMenuDom = 'nc-cnb .ncc-depth2-list-wrap .ncc-depth2-list-items.selected a';\n customTheme.theme[selectedMenuDom] = jQuery.extend(customTheme.theme[selectedMenuDom], {\n borderColor: bar,\n });\n }\n }\n }\n }\n\n // set style\n const style = config.theme.style;\n if (!isEmpty(style)) {\n customTheme = merge(customTheme, this.getCustomStyle(style));\n }\n\n this.__style = merge(this.__style, customTheme);\n }\n\n /*if(this.__sheet) {\n this.__sheet.detach();\n }\n\n this.__sheet = jss.createStyleSheet(this.__style);\n this.__sheet.attach();*/\n\n if (this.__jss.stylesheet !== '') {\n this.__jss.detach();\n }\n\n let stylesheet = this.__jss.createStyleSheet(this.__style);\n this.__jss.attach(stylesheet);\n }\n\n getCustomStyle(style) {\n const root = '#nc-cnb';\n\n let value = { theme: {} };\n let props = keys(style);\n jQuery.each(props, (i, o) => {\n if (/@media/gi.test(o)) {\n value[o] = this.getCustomStyle(style[o]);\n } else {\n const hasRootSelector = new RegExp('^' + root, 'i').test(o);\n const selector = hasRootSelector ? `&${o}` : `&${root} ${o}`;\n value.theme[selector] = style[o];\n }\n });\n\n return value;\n }\n\n getBIStyle(data, isExtend = true) {\n if (isEmpty(data)) {\n return {};\n }\n\n if (isEmpty(data.path)) {\n return data.style || {};\n }\n\n let img = {\n textIndent: '-9999em',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n backgroundSize: 'cover',\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'center center',\n };\n\n let styleObj = jQuery.extend({}, { backgroundImage: `url(${data.path})` }, data.style);\n\n if (isExtend) {\n // styleObj.extend = img;\n styleObj = jQuery.extend({}, styleObj, img);\n }\n\n return styleObj;\n }\n\n get style() {\n return this.__style;\n }\n\n get classes() {\n // return this.__sheet.classes;\n return { theme: this.__jss.name };\n }\n\n /*hexToRGB(hex, alpha) {\n var r = parseInt(hex.slice(1, 3), 16),\n g = parseInt(hex.slice(3, 5), 16),\n b = parseInt(hex.slice(5, 7), 16);\n\n if (alpha) {\n return \"rgba(\" + r + \", \" + g + \", \" + b + \", \" + alpha + \")\";\n } else {\n return \"rgb(\" + r + \", \" + g + \", \" + b + \")\";\n }\n }*/\n}\n\nclass Jss {\n constructor($name) {\n this._name = $name;\n this._stylesheet = '';\n\n this._uppercasePattern = /[A-Z]/g;\n this._msPattern = /^ms-/;\n this._cache = {};\n\n this.IS_UNITLESS = {\n animationIterationCount: true,\n boxFlex: true,\n boxFlexGroup: true,\n boxOrdinalGroup: true,\n columnCount: true,\n flex: true,\n flexGrow: true,\n flexPositive: true,\n flexShrink: true,\n flexNegative: true,\n flexOrder: true,\n gridRow: true,\n gridColumn: true,\n fontWeight: true,\n lineClamp: true,\n lineHeight: true,\n opacity: true,\n order: true,\n orphans: true,\n tabSize: true,\n widows: true,\n zIndex: true,\n zoom: true,\n\n // SVG-related properties\n fillOpacity: true,\n stopOpacity: true,\n strokeDashoffset: true,\n strokeOpacity: true,\n strokeWidth: true,\n };\n }\n\n get name() {\n return this._name;\n }\n\n get stylesheet() {\n return this._stylesheet;\n }\n\n attach(stylesheet) {\n this._stylesheet = stylesheet;\n this._stylesheetDom = jQuery(``);\n this._stylesheetDom.appendTo(jQuery('head'));\n }\n\n detach() {\n if (this._stylesheetDom) {\n this._stylesheetDom.remove();\n }\n }\n\n createStyleSheet($obj) {\n let keys = Object.keys($obj);\n let i,\n len = keys.length;\n let result = '';\n\n for (i = 0; i < len; i++) {\n let key = keys[i];\n let val = $obj[key];\n\n if (key === 'theme') {\n result += this.createStyleSheet(val);\n } else if (/@media/gi.test(key)) {\n result += key + '{' + this.createStyleSheet(val) + '}';\n } else {\n let markup = this.createStyleSheetMarkup(val);\n if (markup !== '') {\n result += '.' + this._name + key.replace('&', '') + '{' + markup + '}';\n }\n }\n }\n\n return result;\n }\n\n createStyleSheetMarkup($style) {\n let keys = Object.keys($style);\n let i,\n len = keys.length;\n let result = '';\n\n for (i = 0; i < len; i++) {\n let key = keys[i];\n let val = $style[key];\n\n if (typeof val !== 'undefined' && !isObject(val)) {\n result += this.hyphenate(key) + ':' + this.addPx(key, val) + ';';\n }\n }\n\n return result;\n }\n\n hyphenate(string) {\n let cache = this._cache;\n let uppercasePattern = this._uppercasePattern;\n let msPattern = this._msPattern;\n return string in cache\n ? cache[string]\n : (cache[string] = string\n .replace(uppercasePattern, '-$&')\n .toLowerCase()\n .replace(msPattern, '-ms-'));\n }\n\n addPx(name, value) {\n if (typeof value === 'number' && !this.IS_UNITLESS[name]) {\n return value + 'px';\n } else {\n return value;\n }\n }\n}\n\nexport default Theme;\n","import Theme from './theme';\nimport isEmpty from 'lodash/isEmpty';\n\nexport const CNB_TYPE = {\n NONE: '',\n A: 'A',\n B: 'B',\n C: 'C',\n D: 'D',\n};\n\n/*\n * CNBV TYPe\n *\n * A : 게임 사이트\n * B : 게임 프로모션, 업데이트 연대기 사이트\n * C : 회원 사이트 (마이페이지, 고객센터, N샵)\n * D : 기타 사이트 (메인, 약관/정책, 공지사항, 장기 미이용 복귀 센터, 게임시간선택제)\n *\n */\n\nlet singleton = null;\nlet singletonEnforcer = 'singletonEnforcer';\n\nclass Common {\n constructor(enforcer) {\n if (enforcer !== singletonEnforcer) {\n throw 'Cannot--construct singleton';\n }\n }\n\n static get instance() {\n if (!singleton) {\n singleton = new Common(singletonEnforcer);\n }\n return singleton;\n }\n\n init() {\n this.__isMobile = /(iPhone|iPod|iPad|Android|NC Noob)/i.test(navigator.userAgent);\n const href = window.location.href;\n\n const subdomain = {\n opdev: ['op.', 'opdev.', 'op-', 'opdev-', 'local.', 'localhost', 'ui-static', 'file:'],\n rc: ['rc.', 'rc-', 'rc2-'],\n sb: ['sb.', 'sb-'],\n };\n\n this.__env = 'live';\n for (let prop in subdomain) {\n const matchs = subdomain[prop];\n const regexp = new RegExp(`^http[s]?:\\\\/\\\\/(${matchs.join('|')})+.*`, 'i');\n if (regexp.test(href)) {\n this.__env = prop;\n }\n }\n\n const staticurls = {\n opdev: 'https://op-wstatic.ncsoft.com',\n rc: 'https://rc-wstatic.plaync.co.kr',\n sb: 'https://sb-wstatic.plaync.com',\n live: 'https://wstatic-cdn.plaync.com',\n };\n this.__staticHost = staticurls[this.__env];\n\n this.__config = {};\n this.__defaultConfig = {\n type: '',\n bi: {},\n };\n }\n\n setShortCutData(data, config) {\n if (typeof config === 'undefined') return data;\n\n let resetData = {};\n jQuery.each(data, key => {\n if (typeof config[key] !== 'undefined') {\n resetData[key] = config[key];\n }\n });\n\n // check url\n jQuery.each(resetData, (key, obj) => {\n if (typeof obj === 'object') {\n if (isEmpty(obj.url)) {\n obj.url = undefined;\n }\n }\n });\n\n return jQuery.extend(true, {}, data, resetData);\n }\n\n setShortCutUrl(data, config) {\n jQuery.each(data, key => {\n const { url } = data[key];\n\n if (url && config[key]) {\n const cUrl = config[key].url;\n if (cUrl === '' || typeof cUrl === 'undefined') {\n config[key].url = url;\n }\n }\n });\n\n return config;\n }\n\n get staticHost() {\n return this.__staticHost;\n }\n\n get isMobile() {\n return this.__isMobile;\n }\n\n get env() {\n return this.__env;\n }\n\n set config(_config) {\n // let isPc = !this.__isMobile;\n // let isRcDash = (this.__env === 'rc') ? 'rc-' : '';\n // let isRc2Dash = (this.__env === 'rc') ? 'rc2-' : '';\n\n // default 설정 : 아래 4개의 숏컷은 항상 노출되도록 isShow: true 강제로 지정한다.\n this.__shortCutData = {\n isShow: true,\n charHome: { isShow: true, url: '/my/profile/character' },\n mypage: {\n isShow: true,\n type: '',\n // url: 'https://' + isRcDash + 'id.plaync.com/index'\n url: '',\n },\n ncoin: {\n isShow: true,\n type: 'popup',\n popOption: 'width=480,height=650,toolbar=0,menubar=0',\n // url: 'https://' + isRc2Dash + 'ncoin.plaync.com/ncoin/charge'\n url: '',\n },\n enterCoupon: {\n isShow: true,\n type: 'function',\n name: 'nshop.popup',\n params: { popup_service: 'nshop_coupon' },\n },\n cs: {\n isShow: true,\n type: '', // external\n // url: isPc ? 'https://' + isRcDash + 'cs.plaync.com/inquiry/list/view' : 'https://' + isRcDash + 'mcs.plaync.com/info'\n url: '',\n },\n security: {\n isShow: false,\n type: '', // external\n // url: isPc ? 'https://' + isRcDash + 'cs.plaync.com/inquiry/list/view' : 'https://' + isRcDash + 'mcs.plaync.com/info'\n url: '',\n },\n };\n\n this.__config = jQuery.extend(true, {}, this.__defaultConfig, _config);\n this.__config.type = (this.__config.type || this.__config.cnbType || '').toUpperCase();\n this.__config.userData = jQuery.extend(\n true,\n {},\n {\n accountState: { case: 0, msg: '' },\n },\n window.userData,\n );\n this.__config.serviceListData = window.cnbServiceListData;\n this.__config.bannerData = window.cnbBannerData;\n\n // defalut 설정 덮어씌우기.\n this.__shortCutData = this.setShortCutData(this.__shortCutData, _config.shortCut);\n\n // this.__config.shortCut = jQuery.extend(true, {}, window.cnbShortcutData, this.__shortCutData);\n // cnbShortcutData의 url만 체크해서 가져오자\n this.__config.shortCut = this.setShortCutUrl(window.cnbShortcutData, this.__shortCutData);\n\n // simpleCNB 속성 예외처리\n if (this.__config.simpleCNB) {\n this.__config.type = 'B';\n }\n\n switch (this.__config.type) {\n case CNB_TYPE.A:\n break;\n case CNB_TYPE.B:\n this.__config.useJoinMenu = false;\n this.__config.lnbData = [];\n if (this.__config.search) this.__config.search.isShow = false;\n this.__config.useGameStart = 'false';\n break;\n case CNB_TYPE.D:\n this.__config.lnbData = [];\n case CNB_TYPE.C:\n this.__config.useGameStart = 'false';\n if (this.__config.search) this.__config.search.isShow = false;\n break;\n }\n\n // set theme...\n if (typeof this.__theme === 'undefined') {\n this.__theme = new Theme();\n }\n if (this.__config.type === 'C' || this.__config.type === 'D') {\n this.__config.header = {};\n }\n this.__theme.update(this.__config);\n }\n\n get config() {\n return this.__config;\n }\n\n get theme() {\n return this.__theme;\n }\n}\n\nexport default Common;\n","let singleton = null;\nlet singletonEnforcer = 'singletonEnforcer';\n\nclass Dimmed {\n constructor(enforcer) {\n if (enforcer !== singletonEnforcer) {\n throw 'Cannot--construct singleton';\n }\n }\n\n static get instance() {\n if (!singleton) {\n singleton = new Dimmed(singletonEnforcer);\n }\n return singleton;\n }\n\n init() {\n this.dimmed = jQuery('#nc-cnb .ncc-dimmed');\n\n if (this.dimmed.length < 1) {\n this.dimmed = jQuery('
').appendTo('#nc-cnb');\n }\n\n this.dimmed.on('touchstart touchmove touchend', e => {\n // e.preventDefault();\n e.stopPropagation();\n });\n\n this.dimmed.off('click').on('click', e => {\n this.openClose(false);\n return false;\n });\n }\n\n openClose(_isOpen = true, _posi = 'left') {\n if (_isOpen) {\n jQuery('.ncc-' + _posi + '-panel').addClass('is-active');\n this.dimmed.addClass('is-active-' + _posi);\n jQuery('body').css({\n width: '100%',\n position: 'fixed',\n 'margin-top': '-' + jQuery('body').scrollTop() + 'px',\n });\n } else {\n jQuery('.ncc-left-panel, .ncc-right-panel, .ncc-character-panel').removeClass('is-active');\n this.dimmed.removeClass('is-active-left is-active-right is-active-title-submenu');\n jQuery('.ncc-lnb-title--item').hide();\n\n let mTop = Math.abs(\n jQuery('body')\n .css('margin-top')\n .replace('px', ''),\n );\n jQuery('body').attr({ style: '' });\n jQuery('body').scrollTop(mTop);\n }\n jQuery('body').toggleClass('ncc-dimmed', _isOpen);\n\n jQuery(this).trigger('open', { show: _isOpen, pos: _posi });\n }\n}\n\nexport default Dimmed;\n","import Common from './Common';\nimport Dimmed from './Dimmed';\n\nclass AbsModule {\n constructor(_data, _isShow = true) {\n if (this.constructor === AbsModule) {\n throw new TypeError('Cannot construct AbsModule instances directly');\n }\n\n this.com = Common.instance;\n this.dim = Dimmed.instance;\n this.moduleData = _data;\n this.isShow = _isShow;\n }\n\n get markUp() {\n if (!this.isShow) {\n return '';\n } else {\n return this.makeMarkup();\n }\n }\n\n makeMarkup() {}\n\n start() {\n if (!this.isShow) {\n return false;\n } else {\n this.startSetting();\n }\n }\n\n startSetting() {}\n}\n\nexport default AbsModule;\n","import AbsModule from '../common/AbsModule';\nimport { CNB_TYPE } from '../common/Common';\n\nclass Login extends AbsModule {\n startSetting() {\n jQuery(\n '#nc-cnb .ncc-login--info a, #nc-cnb .ncc-login--mobile .ncc-login--mobile-btn, #nc-cnb .ncc-login--user-btn',\n )\n .off('click')\n .on('click', e => {\n this.dim.openClose(true, 'right');\n\n if (typeof window.ncNotice === 'object') {\n window.ncNotice.start();\n }\n // return false;\n e.preventDefault();\n });\n\n jQuery('#nc-cnb .ncc-login--before .ncc-login__link-login')\n .off('click')\n .on('click', e => {\n let callbackFN = this.moduleData.loginFN;\n if (typeof callbackFN === 'string' && typeof window[callbackFN] === 'function') {\n callbackFN = window[callbackFN];\n }\n if (typeof callbackFN === 'function') {\n callbackFN();\n }\n // return false;\n e.preventDefault();\n });\n\n jQuery('#nc-cnb .ncc-login-simple--after .ncc-logout__link-logout')\n .off('click')\n .on('click', e => {\n let callbackFN = this.moduleData.logoutFN;\n if (typeof callbackFN === 'string' && typeof window[callbackFN] === 'function') {\n callbackFN = window[callbackFN];\n }\n if (typeof callbackFN === 'function') {\n callbackFN();\n }\n // return false;\n e.preventDefault();\n });\n }\n\n makeMarkup() {\n let joinURL = this.moduleData.joinURL;\n if (window.cnbLoginData && window.cnbLoginData.signup) {\n joinURL = window.cnbLoginData.signup;\n }\n\n let htmlstr = '';\n if (this.moduleData.userData.isLogin) {\n htmlstr = this.loginAfter(this.moduleData.userData);\n } else {\n htmlstr = `\n
\n `;\n }\n\n return `\n\t\t
\n\t\t ${htmlstr}\n\t\t
`;\n }\n\n loginAfter(_userData) {\n /*\n 1 : 프로필 이미지 + 상태 메시지\n 2 ~ 6 : 프로필 이미지 + ncAccount 닉네임\n 7 ~ : 프로필 이미지 + gameAccount 닉네임 + 서버정보\n */\n const accountType = _userData.uesAccountType || _userData.useAccountType;\n const ncAccount = _userData.ncAccount,\n gameAccount = _userData.gameAccount;\n\n let accountState = this.moduleData.userData.accountState;\n accountState = jQuery.isArray(accountState) ? accountState[0] || {} : accountState;\n\n let caseNum = parseInt(accountState.case || 0, 10);\n if (accountType === 'ncAccount' && caseNum > 0 && caseNum < 3) {\n caseNum += 8;\n }\n\n let userInfo = accountType === 'gameAccount' ? gameAccount : ncAccount;\n let userName = userInfo.name !== '' ? userInfo.name : ncAccount.name;\n let profileImage = userInfo.profileImage !== '' ? userInfo.profileImage : ncAccount.profileImage;\n\n const serverInfo = this.getSubData(userInfo.subData);\n const showServerInfo = accountType === 'gameAccount' && (caseNum < 1 || caseNum > 6) && serverInfo !== '';\n const useUserInfo =\n typeof this.moduleData.useUserInfo === 'undefined' ? true : this.moduleData.useUserInfo;\n const cnbType = useUserInfo ? this.moduleData.type : 'B';\n\n let accountStateMsg = accountState.msg;\n if (accountStateMsg) {\n accountStateMsg = accountStateMsg.replace(/
/gi, ' ');\n }\n\n let loginAfterMarkup = '';\n\n switch (cnbType) {\n /*case CNB_TYPE.B:\n loginAfterMarkup = `\n
\n `;\n break;\n case CNB_TYPE.A :\n case CNB_TYPE.C :\n case CNB_TYPE.D :*/\n default:\n loginAfterMarkup = `\n
\n
\n
\n
\n 0\n \n
\n
\n
\n `;\n }\n\n return loginAfterMarkup;\n }\n\n getSubData(data) {\n if (typeof data === 'undefined') return '';\n let list = data.filter(it => {\n return it.value !== '' && it.value !== 'Lv';\n });\n return list.map(it => it.value).join(', ');\n }\n\n loginStatus(statusData) {\n return `서비스 이용을 위해 본인확인이 필요합니다.
${cnbL10NData.Common.IDVerification}`;\n }\n\n notiFriendCount() {\n return `\n\t\t
${cnbL10NData.Common.Notifications} 0\n\t\t`;\n }\n}\n\nexport default Login;\n","import AbsModule from '../common/AbsModule';\n\nclass GameStart extends AbsModule {\n makeMarkup() {\n let tmpl = '';\n\n if (this.moduleData.useGameStart === 'gameStart') {\n tmpl = `
${this.moduleData.gameStart.markUp}
`;\n } else if (this.moduleData.useGameStart === 'mobileGameDown') {\n tmpl = `\n
\n ${\n this.moduleData.mobileGameDown.showAndro\n ? `
android downlaod`\n : ''\n }\n ${\n this.moduleData.mobileGameDown.showIos\n ? `
ios downlaod`\n : ''\n }\n
`;\n }\n\n return `
${tmpl}
`;\n }\n}\n\nexport default GameStart;\n","import AbsModule from '../common/AbsModule';\nimport Common from '../common/Common';\n\nclass Search extends AbsModule {\n startSetting() {\n if (typeof this.moduleData.search === 'undefined') return;\n this.showSearchBar = false;\n\n jQuery('.ncc-search').click(function(e) {\n e.stopPropagation();\n });\n\n const me = this;\n jQuery('.ncc-search legend').on('click', function(e) {\n e.preventDefault();\n me.showSearchField();\n });\n\n jQuery('.ncc-search-close').on('click', () => {\n this.hideSearchField();\n return false;\n });\n\n if (typeof window.AutoSuggest === 'undefined') {\n const path = '/uikit/autosuggest/v1/js/AutoSuggest.js';\n let host = Common.instance.staticHost;\n\n const scripts = jQuery(\"script[src*='/autosuggest/']\");\n if (scripts.length === 0) {\n jQuery.getScript(host + path, () => {\n me.setAutoSuggest();\n });\n } else {\n setTimeout(() => {\n me.setAutoSuggest();\n }, 100);\n }\n } else {\n me.setAutoSuggest();\n }\n }\n\n setAutoSuggest() {\n const searchData = this.moduleData.search;\n const autoSuggest = new AutoSuggest();\n const queryStr = searchData.queryPattern || '?';\n\n autoSuggest.init({\n selector: '#nccSuggestForm',\n service: searchData.service,\n alias: searchData.alias,\n size: searchData.size,\n useDelbtn: searchData.useDelbtn,\n addParam: searchData.addParam || {},\n submitCallback: function(_q) {\n const _href =\n searchData.destUrl +\n queryStr +\n jQuery.param({\n query: _q,\n // where : this.moduleData.search.where,\n // pos : this.moduleData.search.pos\n site: searchData.service,\n });\n location.href = _href;\n },\n });\n }\n\n resetSearchField() {\n jQuery('.ncc-search-input').val('');\n jQuery('.ncc-search-input-delete').hide();\n }\n\n showSearchField() {\n if (this.showSearchBar) return;\n jQuery('.ncc-search').addClass('is-active');\n jQuery('.ncc-search legend')\n .hide()\n .animateCss('fadeIn');\n jQuery('.ncc-lnb').addClass('search-active');\n\n window.setTimeout(() => {\n jQuery('.ncc-search-input')\n .click()\n .focus();\n // jQuery('.ncc-search-wrap').css('overflow', 'visible');\n }, 300);\n\n /*\n 모바일 디바이스에서 키보트 show/hide를 감지하기 위한 편법..\n\n jQuery(document).ready(function(){\n var _originalSize = jQuery(window).width() + jQuery(window).height()\n jQuery(window).resize(function(){\n if(jQuery(window).width() + jQuery(window).height() != _originalSize){\n console.log(\"keyboard show up\");\n }else{\n console.log(\"keyboard closed\");\n }\n });\n });\n */\n\n jQuery(document).on('click.search', this.hideSearchField.bind(this));\n this.showSearchBar = true;\n }\n\n hideSearchField() {\n jQuery('.ncc-search').removeClass('is-active');\n jQuery('.ncc-search legend')\n .show()\n .animateCss('fadeIn');\n jQuery('.ncc-lnb').removeClass('search-active');\n // jQuery('.ncc-search-wrap').css('overflow', 'hidden');\n\n this.resetSearchField();\n jQuery(document).off('click.search');\n this.showSearchBar = false;\n }\n\n makeMarkup() {\n let positionCls = ' ncc-search--right-no';\n\n if (this.moduleData.useGameStart === 'gameStart') {\n positionCls = ' ncc-search--right-pc';\n }\n\n if (this.moduleData.useGameStart === 'mobileGameDown') {\n if (this.moduleData.mobileGameDown.showAndro && !this.moduleData.mobileGameDown.showIos)\n positionCls = ' ncc-search--right-mo1';\n if (!this.moduleData.mobileGameDown.showAndro && this.moduleData.mobileGameDown.showIos)\n positionCls = ' ncc-search--right-mo1';\n if (this.moduleData.mobileGameDown.showAndro && this.moduleData.mobileGameDown.showIos)\n positionCls = ' ncc-search--right-mo2';\n }\n\n if (window.userData.isLogin) {\n positionCls += ' is-login';\n }\n\n return `\n
\n
\n
`;\n }\n\n makeForm() {\n const search = this.moduleData.search || {};\n let placeHolder = '통합검색';\n if (search.placeholder && search.placeholder !== '') {\n placeHolder = search.placeholder;\n }\n\n let formEle = `\n
\n `;\n\n return formEle;\n }\n}\n\nexport default Search;\n","import { isMobile } from './util';\n\nfunction lnbMarkup(lnbData, isSub = false, active) {\n if (typeof lnbData === 'undefined') return '';\n\n const getClass = idx => {\n return !isSub\n ? 'ncc-lnb-item m' + (idx + 1) + (active.d1 === idx + 1 ? ' is-active' : '')\n : 's' + (idx + 1) + (active.d2 === idx + 1 ? ' is-active' : '');\n };\n\n const getListItem = (item, idx) => {\n const {\n iconType = '',\n title = '',\n url = '',\n popName = 'cnbPopup',\n popOption = '',\n popInPCOnly = '',\n } = item;\n\n let type = iconType;\n if (popInPCOnly === 'true' || popInPCOnly === true) {\n if (type === 'popup' && isMobile) {\n type = '';\n }\n }\n\n let props = `href=\"${item.url}\"`; // Default\n let icon = '';\n\n switch (type) {\n case 'external':\n props += ` target=\"_blank\"`;\n icon = `
external`;\n break;\n case 'popup':\n props = `href=\"javascript:void(0)\" onclick=\"window.open('${url}', '${popName}', '${popOption}').focus();return false;\"`;\n icon = `
popup`;\n break;\n case 'new':\n icon = `
N`;\n break;\n default:\n props += ` target=\"_self\"`;\n break;\n }\n\n const subList =\n item.sub && item.sub.length > 0\n ? lnbMarkup(\n item.sub,\n true,\n active.d1 === idx + 1\n ? active\n : {\n d1: 0,\n d2: 0,\n },\n )\n : '';\n\n return `
${title}${icon}${subList}`;\n };\n\n const list = lnbData\n .map((item, idx) => `
${getListItem(item, idx)}`)\n .join('\\n ');\n\n return `
`;\n}\n\nexport default lnbMarkup;\n","import AbsModule from '../common/AbsModule';\nimport lnbMaker from '../common/LnbMarkup';\n\nconst $ = jQuery;\n\nclass Lnb extends AbsModule {\n constructor(_config) {\n super(_config);\n this.disabled = !$.isArray(_config.lnbData) || _config.lnbData.length === 0;\n }\n\n startSetting() {\n if (this.disabled) return;\n\n this.hoverBar = $('#nc-cnb .ncc-lnb-hover');\n this.hoverBarHalf = this.hoverBar.width() / 2;\n this.hoverBarPos = 50;\n\n const { active = {} } = this.moduleData;\n const isMain = !active.d1 && !active.d2;\n // console.log(active);\n let timeoutID = null;\n\n if (isMain) {\n $('.ncc-lnb').addClass('ncc-lnb-type--main');\n }\n\n // menu items\n $('#nc-cnb')\n .on('mouseenter', '.ncc-lnb .ncc-lnb-item', e => {\n if (isMain) {\n $('.ncc-lnb').addClass('ncc-lnb-type--main-over');\n }\n const $target = $(e.currentTarget);\n const $lnbList = $target.closest('.ncc-lnb-list');\n\n $lnbList.find(`li.m${active.d1}`).removeClass('is-active');\n $target.addClass('is-over');\n\n if (timeoutID) {\n clearTimeout(timeoutID);\n timeoutID = null;\n }\n const targetIndex = $target.index() + 1;\n if (targetIndex === active.d1) {\n this.hoverBarMove(targetIndex, active.d2);\n } else {\n this.hoverBarMove(targetIndex);\n }\n return false;\n })\n .on('mouseleave', '.ncc-lnb .ncc-lnb-item', e => {\n if (isMain) {\n $('.ncc-lnb').removeClass('ncc-lnb-type--main-over');\n }\n const $target = $(e.currentTarget);\n const $lnbList = $target.closest('.ncc-lnb-list');\n\n $target.removeClass('is-over');\n $lnbList.find(`li.m${active.d1}`).addClass('is-active');\n\n /*timeoutID = setTimeout(() => {\n this.hoverBarMove(active.d1, active.d2);\n }, 100);*/\n return false;\n });\n\n // sub items\n $('#nc-cnb')\n .on('mouseenter', '.ncc-lnb .ncc-lnb-item .ncc-lnb-item__sub li', e => {\n const $target = $(e.currentTarget);\n const $lnbList = $target.closest('.ncc-lnb-list');\n const $activeTarget = $lnbList.find(`li.m${active.d1} .ncc-lnb-item__sub li.s${active.d2}`);\n\n $activeTarget.removeClass('is-active');\n $target.addClass('is-active');\n\n if (timeoutID) {\n clearTimeout(timeoutID);\n timeoutID = null;\n }\n this.hoverBarMove($target.closest('.ncc-lnb-item').index() + 1, $target.index() + 1);\n return false;\n })\n .on('mouseleave', '.ncc-lnb .ncc-lnb-item .ncc-lnb-item__sub li', e => {\n const $target = $(e.currentTarget);\n const $lnbList = $target.closest('.ncc-lnb-list');\n const $activeTarget = $lnbList.find(`li.m${active.d1} .ncc-lnb-item__sub li.s${active.d2}`);\n\n $target.removeClass('is-active');\n $activeTarget.addClass('is-active');\n\n timeoutID = setTimeout(() => {\n this.hoverBarMove(active.d1, active.d2);\n }, 30);\n // return false;\n });\n\n this.hoverBarMove(active.d1, active.d2);\n }\n\n hoverBarMove(_d1 = 0, _d2 = 0) {\n const el = $(`#nc-cnb .ncc-lnb .ncc-lnb-list li.m${_d1} .ncc-lnb-item__sub li.s${_d2}`);\n\n const hoverBarScale = el.length ? (((94 * el.width()) / 100) * 0.01 * 1.4).toFixed(2) : 0.1;\n let hoverBarOpacity = el.length ? 1 : 0;\n\n if (el.length && el.offset().left > 0) {\n const elCenterPos = el.offset().left + el.width() / 2;\n this.hoverBarPos = parseInt(elCenterPos - this.hoverBarHalf, 10);\n }\n\n if (this.hoverBar) {\n this.hoverBar.css({\n transform: `translateX(${this.hoverBarPos}px) scaleX(${hoverBarScale})`,\n opacity: hoverBarOpacity,\n });\n }\n }\n\n makeMarkup() {\n return `\n
`;\n }\n}\n\nexport default Lnb;\n","import AbsModule from '../common/AbsModule';\nimport Templater from '../common/templater';\nimport _find from 'lodash/find';\n\nclass LnbDropdown extends AbsModule {\n constructor(_prefix, _data, _isShow = true) {\n super(_data, _isShow);\n this.prefix = `${_prefix}-dropdown`;\n }\n\n startSetting() {\n const $dropdown = jQuery(`.ncc-dropdown.${this.prefix}`);\n this.$dropdown = $dropdown;\n\n const dropdownItemHeight =\n parseInt(\n $dropdown\n .find('.dropdown-item')\n .first()\n .css('height'),\n 10,\n ) + 3;\n\n this.dropdownMenuHeight = this.itemSize * (dropdownItemHeight + 1) - 1;\n\n /*switch (this.actionType) {\n case 'click':\n break;\n case 'hover':\n break;\n }*/\n\n $dropdown.find('.dropdown-toggle.btn').click(() => {\n this.toggle();\n return false;\n });\n }\n\n toggle() {\n const $toggleBtn = this.$dropdown.find('.dropdown-toggle.btn');\n const $menu = this.$dropdown.find('.dropdown-menu');\n $toggleBtn.toggleClass('is-active');\n $menu.toggleClass('is-active');\n\n const isActive = $toggleBtn.hasClass('is-active');\n $toggleBtn.attr('aria-expanded', isActive);\n $menu.find('.dropdown-menu-wrap').css('max-height', isActive ? this.dropdownMenuHeight : 0);\n\n if (isActive) {\n jQuery(document).on(`click.${this.prefix}`, this.toggle.bind(this));\n } else {\n jQuery(document).off(`click.${this.prefix}`);\n }\n }\n\n makeMarkup() {\n const { lnbDropdown = {} } = this.moduleData;\n const { items, action } = lnbDropdown;\n\n this.actionType = action;\n this.itemSize = items.length;\n\n const targetItem = _find(items, o => o.selected);\n const $toggleBtn = `\n \n `;\n\n const itemTemplate = Templater`\n
\n ${'title'}\n `;\n const $itemButtons = items.map(o => itemTemplate(o)).join('');\n\n return `\n
\n ${$toggleBtn}\n \n
`;\n }\n}\n\nexport default LnbDropdown;\n","export default function(strings, ...keys) {\n return function(data) {\n let temp = strings.slice();\n keys.forEach((key, i) => {\n // key=\"value\" 형태로 사용한다.\n const attrs = key.split('.');\n if (attrs.length > 1) {\n key = attrs[1];\n const value = data[key];\n\n if (value && value !== '') {\n temp[i] = temp[i] + attrs[0] + '=\"' + data[key] + '\"';\n }\n } else {\n temp[i] = temp[i] + data[key];\n }\n });\n return temp.join('');\n };\n}\n","import * as Util from './util';\n\nclass SwipeMove {\n constructor(_container, _itemSelector, _nowNum) {\n this.container = jQuery(_container);\n this.mover = this.container.children().eq(0);\n this.items = this.container.find(_itemSelector);\n this.itemLength = this.items.length;\n this.scrollerWidth = 0;\n this.targetX = 0;\n this.isTooBig = false;\n this.nowNum = _nowNum;\n\n this.isShowStatus = false;\n this.itemSelector = _itemSelector;\n\n if (this.mover.length) {\n this.setScroll(_itemSelector);\n this.winResize();\n this.addEvents();\n }\n }\n\n addEvents() {\n jQuery(window).on('resize.swipemove', e => this.winResize(e));\n this.mover.on('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', e =>\n this.transitionDuration(this.mover),\n );\n if (!Util.isMobile) {\n this.container.on('mousedown', e => this.moveStart(e));\n jQuery(window).on('mousemove', e => this.moveMove(e));\n jQuery(window).on('mousecancel mouseup', e => this.moveEnd(e));\n } else {\n this.container.on('touchstart', e => this.moveStart(e));\n this.container.on('touchmove', e => this.moveMove(e));\n this.container.on('touchcancel touchend', e => this.moveEnd(e));\n }\n }\n\n winResize() {\n if (window.innerWidth < 960) {\n if (!this.isShowStatus) this.setScroll(this.itemSelector);\n this.isShowStatus = true;\n } else {\n this.isShowStatus = false;\n }\n this.isTooBig = this.container[0].clientWidth > this.scrollerWidth;\n this.resetPosition();\n }\n\n resetPosition() {\n let moveX = 0;\n if (this.isTooBig) {\n // moveX = (this.container[0].clientWidth - this.scrollerWidth) / 2;\n moveX = 1;\n } else {\n let item = jQuery(this.items[this.nowNum - 1]);\n if (item.length) moveX = -item.position().left;\n\n if (moveX < this.container[0].clientWidth - this.scrollerWidth) {\n moveX = this.container[0].clientWidth - this.scrollerWidth;\n }\n if (moveX > 0) {\n moveX = 0;\n }\n }\n\n this.transitionTimingFunction(this.mover);\n this.transitionDuration(this.mover, '200');\n this.translate(this.mover, moveX);\n }\n\n moveStart(e) {\n e.stopPropagation();\n this.isStart = true;\n let point = e.originalEvent.touches ? e.originalEvent.touches[0] : e.originalEvent;\n this.startX = point.pageX;\n this.tx = this.targetX;\n }\n\n moveMove(e) {\n e.stopPropagation();\n if (!this.isStart || this.isTooBig) return;\n this.mover.css({\n 'pointer-events': 'none'\n });\n let point = e.originalEvent.touches ? e.originalEvent.touches[0] : e.originalEvent;\n let newX = this.tx + point.pageX - this.startX;\n this.translate(this.mover, newX);\n }\n\n moveEnd(e) {\n if (!this.isStart || this.isTooBig) return;\n this.isStart = false;\n this.mover.css({\n 'pointer-events': 'auto'\n });\n\n if (this.targetX > 0) {\n this.transitionDuration(this.mover, '200');\n this.translate(this.mover, 0);\n }\n if (this.targetX < this.container[0].clientWidth - this.scrollerWidth) {\n this.transitionDuration(this.mover, '200');\n this.translate(this.mover, this.container[0].clientWidth - this.scrollerWidth);\n }\n }\n\n translate(_target, _x) {\n _target.css(Util.prefixStyle('transform'), 'translate3d(' + parseInt(_x) + 'px, 0, 0)');\n this.targetX = _x;\n }\n\n transitionDuration(target, time = 0) {\n target.css(Util.prefixStyle('transitionDuration'), time + 'ms');\n }\n\n transitionTimingFunction(target, easingFN = 'cubic-bezier(0.1, 0.54, 0.4, 1)') {\n target.css(Util.prefixStyle('transitionTimingFunction'), easingFN);\n }\n\n setScroll(_selector) {\n this.scrollerWidth = 0;\n // let selector = _selector.split(' ');\n // let parentWidth = 0;\n\n for (let i = 0; i < this.itemLength; i++) {\n this.scrollerWidth += Math.ceil(jQuery(this.items[i]).outerWidth());\n this.scrollerWidth += parseInt(jQuery(this.items[i]).css('margin-right'));\n this.scrollerWidth += parseInt(jQuery(this.items[i]).css('margin-left'));\n }\n\n /*if(selector.length > 1){\n for(let i = 0; i < selector.length - 1; i++){\n parentWidth += parseInt(this.mover.find(\">\" + selector[i]).css('padding-left'));\n parentWidth += parseInt(this.mover.find(\">\" + selector[i]).css('padding-right'));\n parentWidth += parseInt(this.mover.find(\">\" + selector[i]).css('margin-right'));\n parentWidth += parseInt(this.mover.find(\">\" + selector[i]).css('margin-right'));\n parentWidth += parseInt(this.mover.find(\">\" + selector[i]).css('border-right-width'));\n parentWidth += parseInt(this.mover.find(\">\" + selector[i]).css('border-left-width'));\n }\n }\n this.scrollerWidth += (parentWidth-15);*/\n\n this.mover.css({\n width: this.scrollerWidth + 2\n });\n }\n}\n\nexport default SwipeMove;","import AbsModule from '../common/AbsModule';\nimport Login from './Login';\nimport GameStart from './GameStart';\nimport Search from './Search';\nimport Lnb from './Lnb';\nimport LnbDropdown from '../components/LnbDropdown';\nimport Swipe from '../common/SwipeMove';\nimport isEmpty from 'lodash/isEmpty';\n\nclass HeaderMain extends AbsModule {\n constructor(_config) {\n super(_config);\n\n jQuery('body').toggleClass('cnb-no-hamburger', !this.moduleData.useLeftMenu);\n\n this.setMenuActive();\n\n this._con = '#nc-cnb .ncc-header ';\n this._login = new Login(_config, _config.useLoginMenu);\n this._gameStart = new GameStart(_config, !isEmpty(_config.useGameStart) && _config.useGameStart !== '');\n this._search = new Search(_config, !isEmpty(_config.search) && _config.search.isShow);\n this._lnbDropdown = new LnbDropdown('header', _config, !isEmpty(_config.lnbDropdown));\n this._lnb = new Lnb(_config);\n }\n\n escapeSpecialChars(string) {\n return string.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n }\n\n setMenuActive() {\n const lnb = this.moduleData.lnbData;\n const activeMenu = [];\n let hasRegexp = false;\n\n if (typeof this.moduleData.active === 'undefined' && jQuery.isArray(lnb)) {\n const mdata = { d1: 0, d2: 0 };\n const href = window.location.href;\n const locPathName = window.location.pathname;\n\n let i = 0,\n j = 0,\n menu,\n sub,\n urls,\n subUrls,\n isMatch;\n\n for (; i < lnb.length; ++i) {\n menu = lnb[i];\n\n if (jQuery.isArray(menu.sub)) {\n for (j = 0; j < menu.sub.length; ++j) {\n sub = menu.sub[j];\n\n if (sub.regex && sub.regex.pattern) {\n const { pattern, flags } = sub.regex;\n isMatch = new RegExp(pattern, flags).test(locPathName);\n\n if (isMatch) {\n mdata.d1 = i + 1;\n mdata.d2 = j + 1;\n hasRegexp = true;\n break;\n }\n } else {\n subUrls = [sub.url].concat(sub.otherUrls || []);\n isMatch = subUrls.some(url => {\n return new RegExp(this.escapeSpecialChars(url), 'gi').test(href);\n });\n\n if (isMatch) {\n mdata.d1 = i + 1;\n mdata.d2 = j + 1;\n }\n }\n }\n }\n\n // regex\n if (menu.regex && menu.regex.pattern) {\n const { pattern, flags } = menu.regex;\n isMatch = new RegExp(pattern, flags).test(locPathName);\n if (isMatch) {\n mdata.d1 = i + 1;\n hasRegexp = true;\n break;\n }\n } else {\n let matchUrl;\n urls = [menu.url].concat(menu.otherUrls || []);\n\n isMatch = urls.some(url => {\n if (url === '' || url === '/') {\n return false;\n }\n\n // 도메인만 존재하는 경로라면 예외처리\n const match = url.match(/:\\/\\/(?:www\\.)?(.[^/]+)(.*)/);\n if (match && match.length > 2) {\n const pathname = match[2];\n if (pathname === '' || pathname === '/') {\n return false;\n }\n }\n\n const m = new RegExp(this.escapeSpecialChars(url), 'gi').test(href);\n if (m) {\n matchUrl = url;\n }\n return m;\n });\n\n if (isMatch) {\n mdata.d1 = i + 1;\n activeMenu.push({ index: i + 1, matchUrl });\n }\n }\n }\n\n if (!hasRegexp && activeMenu.length > 1) {\n // 중복 체크가 되었을 경우 가장 긴 url 네임을 가진 인덱스를 활성화 한다.\n const activeMenuTarget = activeMenu.reduce((acc, cur) => {\n const url1 = acc.matchUrl;\n const url2 = cur.matchUrl;\n return url1.length > url2.length ? acc : cur;\n });\n\n mdata.d1 = activeMenuTarget.index;\n }\n\n this.moduleData.active = mdata;\n }\n }\n\n startSetting() {\n this._login.start();\n this._gameStart.start();\n this._search.start();\n this._lnbDropdown.start();\n this._lnb.start();\n\n if (!this._lnb.disabled && jQuery('#ncc-depth2-tap').length) {\n let depth =\n this.moduleData.type === 'C' && this.moduleData.useMobileNav\n ? this.moduleData.active.d1\n : this.moduleData.active.d2;\n new Swipe('#ncc-depth2-tap', '.ncc-depth2-list > .ncc-depth2-list-items', depth);\n }\n\n jQuery(this._con + '.ncc-gnb-wrap .ncc-ncservice-btn').on('click', e => {\n this.dim.openClose(true, 'left');\n e.preventDefault();\n });\n\n jQuery(this._con + '.ncc-lnb-wrap .ncc-account-message-close').on('click', e => {\n jQuery(this._con + '.ncc-lnb-wrap .ncc-account-message').hide();\n return false;\n });\n\n let $window = jQuery(window);\n let mobileScreenSize = 960;\n let isMobileScreenSize = $window.outerWidth() < mobileScreenSize;\n\n let onResize = () => {\n if ($window.outerWidth() >= mobileScreenSize) {\n $window.off('resize.lnb');\n this._lnb.hoverBarMove(this.moduleData.active.d1, this.moduleData.active.d2);\n }\n };\n\n let elCNB = jQuery('#nc-cnb');\n let elHeader = jQuery('.ncc-header');\n let nCnbPosY = elHeader.height();\n let posY = nCnbPosY;\n let $winH = jQuery(window).height();\n\n let onScroll = () => {\n // 전체화면일 경우 리턴\n let $docH = jQuery(document).height();\n if ($docH === $winH) {\n elCNB.removeClass('is-sticky');\n return;\n }\n\n // body 상단에 배너가 붙었을 경우 대비\n let offsetTop = (elCNB.offset() && elCNB.offset().top) || 0;\n posY = nCnbPosY + offsetTop;\n\n let scrTop = $window.scrollTop();\n let bodyIsFixed = jQuery('body').css('position') === 'fixed';\n let bodyMarginTop = Math.abs(\n jQuery('body')\n .css('margin-top')\n .replace('px', ''),\n );\n let isSticky = false;\n let isTop = false;\n\n if (scrTop >= offsetTop) isTop = true;\n if (scrTop >= posY) isSticky = true;\n if (bodyIsFixed && bodyMarginTop >= posY) isSticky = true;\n elCNB.toggleClass('is-sticky', isSticky);\n elCNB.toggleClass('is-top', isTop);\n };\n\n $window.scroll(onScroll);\n onScroll();\n\n if (isMobileScreenSize) {\n $window.on('resize.lnb', onResize);\n onResize();\n }\n\n if (this.com.__isMobile) {\n function mobileScr() {\n let scrTop = $window.scrollTop();\n elHeader.toggleClass('fixed', scrTop > 0);\n }\n\n $window.on('scroll touchmove touchstart touchend touchcancel touchforcechange click', mobileScr);\n mobileScr();\n }\n }\n\n makeMarkup() {\n if (this.moduleData.useGameStart === 'false') {\n this.moduleData.useGameStart = false;\n }\n\n let showSearch = this.moduleData.search ? this.moduleData.search.isShow : false;\n let useGameStart = this.moduleData.useGameStart ? this.moduleData.useGameStart : false;\n let lnbWrap =\n !useGameStart && this._lnb.disabled && !showSearch\n ? ''\n : `\n
\n ${this._gameStart.markUp}\n ${this._lnbDropdown.markUp}\n ${this._lnb.markUp}\n
\n `;\n let childNavCls = lnbWrap === '' ? '' : ' is-child-nav';\n let subMrkup = this.makeSubTitleMarkup();\n let is2Depth = subMrkup.indexOf('ncc-depth2-tap') > -1;\n childNavCls = is2Depth ? childNavCls + ' is-2depth' : childNavCls;\n\n return `\n \n `;\n }\n\n makeSubTitleBiMarkup(isHide = false) {\n const { bi = {} } = this.moduleData;\n const isLogoUrl = typeof bi.logo !== 'undefined' && bi.logo !== '';\n const logoTypePlayNC = ( typeof(bi.image) === 'string') ? bi.image.substr(0, 6) === 'plaync' : false;\n\n // logo url을 사용한다면 디폴트 타입: all / 아니면 image\n const defaultBIType = isLogoUrl ? 'all' : 'image';\n\n let biType = bi.type || defaultBIType;\n\n const biCls = logoTypePlayNC ? ' '+ bi.image : '';\n\n const biProps = `class=\"ncc-bi${biCls}\" data-type=\"${biType}\" ${isHide ? 'style=\"display:none;\"' : ''}`;\n let markup = `
${bi.title}`;\n\n // image + text\n if (biType === 'all') {\n markup = `
`;\n }\n\n return markup;\n }\n\n makeSubTitleMarkup() {\n const { d1 = 0, d2 = 0 } = this.moduleData.active;\n let lnbDataD1 = !this._lnb.disabled ? this.moduleData.lnbData[d1 - 1] : false;\n\n // Type C\n if (this.moduleData.type === 'C' && this.moduleData.lnbData && this.moduleData.lnbData.length) {\n if (this.moduleData.useMobileNav) {\n // C타입에서 1뎁스 메뉴 모바일 해상도에서도 고정 노출\n const subArr = this.getSubMenuMarkup(this.moduleData.lnbData, d1);\n const isActive = typeof d1 !== 'undefined' && d1 > 0;\n\n return `${this.makeSubTitleBiMarkup()}\n
\n `;\n } else {\n return `${this.makeSubTitleBiMarkup()}`;\n }\n }\n\n // not Type C\n if (d1 === 0 || !lnbDataD1) {\n return `${this.makeSubTitleBiMarkup()}`;\n } else {\n let subArr = this.moduleData.lnbData[d1 - 1].sub;\n let lnbDataD2 = subArr && subArr[d2 - 1];\n\n const getTitleLink = linkData => {\n return `
${linkData.title}`;\n };\n\n if (d2 === 0 || !lnbDataD2) {\n return `${this.makeSubTitleBiMarkup(this.moduleData.type !== 'C' && this.moduleData.type !== 'D')}\n
`;\n } else {\n return `${this.makeSubTitleBiMarkup(true)}\n
`;\n }\n }\n }\n\n getSubMenuMarkup(sub, selectedIndex) {\n return sub\n .map((item, idx) => {\n let selectedCls = idx + 1 === selectedIndex ? ' selected' : '';\n return `\n
\n \n ${item.title}\n ${item.iconType == 'new' ? `N` : ''}\n ${item.iconType == 'external' ? `external` : ''}\n ${item.iconType == 'popup' ? `popup` : ''}\n \n `;\n })\n .join('\\n ');\n }\n}\n\nexport default HeaderMain;\n","import AbsModule from '../common/AbsModule';\nimport lnbMaker from '../common/LnbMarkup';\n\nclass Lnb extends AbsModule {\n makeMarkup() {\n return `
`;\n }\n}\n\nexport default Lnb;\n","import AbsModule from '../common/AbsModule';\nimport * as Util from '../common/util';\n\nlet uagentLow = navigator.userAgent.toLocaleLowerCase();\nlet isIos = /iphone|ipad/gi.test(uagentLow);\nlet isAndroid = /android/gi.test(uagentLow);\n\nclass AppDownload extends AbsModule {\n startSetting() {\n /*\n jQuery('#nc-cnb').on('click', '.ncc-appdownload .ncc-appdownload-btn', (e)=>{\n document.location.href = isAndroid? jQuery(e.currentTarget).data('andlink'): jQuery(e.currentTarget).data('ioslink');\n return false;\n });\n */\n }\n\n makeMarkup() {\n if (Util.isMobile) {\n var list = '';\n\n if (this.moduleData.appList && this.moduleData.appList.length > 0) {\n list = this.moduleData.appList.map(item => this.makeAppItem(item)).join('\\n ');\n } else {\n for (let key in this.moduleData) {\n if (key == 'isShow' || key == 'appList') continue;\n list += this.makeAppItem(this.moduleData[key]);\n }\n }\n\n return `\n
\n `;\n } else {\n // return `
`;\n return ``;\n }\n }\n\n makeAppItem(_it) {\n let item = '';\n\n if (isIos && _it.iosAppLink) {\n item = `\n
\n \n
\n ${_it.appName}\n \n `;\n }\n\n if (isAndroid && _it.androAppLink) {\n item = `\n
\n \n
\n ${_it.appName}\n \n `;\n }\n\n return item;\n }\n}\n\nexport default AppDownload;\n","import AbsModule from '../common/AbsModule';\n\nclass ServiceList extends AbsModule {\n makeMarkup() {\n let addbottom = '';\n if (navigator.userAgent.indexOf('iPhone OS 15')>0) {\n addbottom = ` style=\"padding-bottom: 100px;\"`;\n }\n\n return `\n
\n
\n \n ${\n !this.moduleData.isServiceShow\n ? ''\n : `\n - \n ${this.moduleData.service\n .map(\n (item, idx) => `\n ${item.title}\n `,\n )\n .join('\\n ')}\n
\n `\n }\n \n ${\n !this.moduleData.isPcShow\n ? ''\n : `\n - \n
${cnbL10NData.Service.PCGames}
\n \n ${this.moduleData.pc\n .map(\n (item, idx) => `\n - \n ${item.title}\n
\n `,\n )\n .join('\\n ')}\n
\n \n `\n }\n \n ${\n !this.moduleData.isMobileShow\n ? ''\n : `\n - \n
${cnbL10NData.Service.MobileGames}
\n \n ${this.moduleData.mobile\n .map(\n (item, idx) => `\n - \n ${item.title}\n
\n `,\n )\n .join('\\n ')}\n
\n \n `\n }\n \n ${\n !this.moduleData.isMobileServiceShow\n ? ''\n : `\n - \n
${cnbL10NData.Service.MobileServices}
\n \n ${this.moduleData.mobileService\n .map(item => {\n return `\n - \n ${item.title}\n
\n `;\n })\n .join('\\n ')}\n
\n \n `\n } \n
\n
\n `;\n }\n}\n\nexport default ServiceList;\n","import AbsModule from '../common/AbsModule';\nimport assign from 'lodash/assign';\n\nclass Banner extends AbsModule {\n startSetting() {}\n\n makeMarkup() {\n let list = [];\n for (let prop in this.moduleData) {\n if (prop !== 'isShow') {\n list.push(assign(this.moduleData[prop], { name: prop }));\n }\n }\n\n const baners_markup = list\n .map(o => {\n let imgPath = this.com.__staticHost + o.imgPath;\n // let style = `background-image: url(${imgPath})`;\n\n return `\n
\n `;\n })\n .join('');\n\n return `\n
\n ${baners_markup} \n
\n `;\n }\n}\n\nexport default Banner;\n","import AbsModule from '../common/AbsModule';\nimport LnbDropdown from '../components/LnbDropdown';\nimport Lnb from './Lnb';\nimport AppDownload from './AppDownload';\nimport ServiceList from './ServiceList';\nimport Banner from './Banner';\nimport isEmpty from 'lodash/isEmpty';\nimport { isMobile } from '../common/util';\n\nclass LeftMain extends AbsModule {\n constructor(_config) {\n super(_config);\n\n this._lnb = new Lnb(_config);\n this._appDownload = new AppDownload(\n _config.appDownloadData,\n !isEmpty(_config.appDownloadData) && _config.appDownloadData.isShow,\n );\n this._serviceList = new ServiceList(\n _config.serviceListData,\n !isEmpty(_config.serviceListData) &&\n (_config.serviceListData.isServiceShow ||\n _config.serviceListData.isPcShow ||\n _config.serviceListData.isMobileShow) &&\n _config.useLeftMenu,\n );\n this._banner = new Banner(_config.bannerData, !isEmpty(_config.bannerData) && _config.bannerData.isShow);\n this._lnbDropdown = new LnbDropdown('left-panel', _config, !isEmpty(_config.lnbDropdown));\n }\n\n startSetting() {\n jQuery('#nc-cnb').on('click', '.ncc-left-panel-close', e => {\n this.dim.openClose(false);\n return false;\n });\n\n this._lnb.start();\n this._appDownload.start();\n this._serviceList.start();\n this._banner.start();\n this._lnbDropdown.start();\n\n jQuery(this.dim).on('open', (e, data) => {\n if (data.show && data.pos === 'left') {\n this.createIScroll();\n }\n });\n\n const $panel = jQuery('.ncc-left-panel');\n if ($panel.length) {\n const panel = $panel[0];\n const stopEvtAction = e => {\n e.preventDefault();\n };\n panel.addEventListener('touchmove', stopEvtAction, { passive: false });\n }\n }\n\n createIScroll() {\n if (this.iScroll) return;\n const isMo = isMobile;\n this.iScroll = new IScroll('.ncc-left-panel-content', {\n scrollbars: true,\n mouseWheel: true,\n interactiveScrollbars: true,\n shrinkScrollbars: 'scale',\n disableMouse: !isMo,\n disablePointer: !isMo,\n fadeScrollbars: true,\n // preventDefault: true,\n preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|A|LI|SPAN|IMG|STRONG)$/ },\n });\n }\n\n destroy() {\n if (this.iScroll) {\n this.iScroll.destroy();\n this.iScroll = null;\n }\n }\n\n makeMarkup() {\n const isPlayNC = ( typeof(this.moduleData.bi.image) === 'string') ? this.moduleData.bi.image.substr(0, 6) === 'plaync' : false;\n\n let brtag = `
`;\n if($('body').hasClass('ANDROID')){\n brtag = `
`;\n }\n\n return `\n
\n
\n \n ${this._lnbDropdown.markUp}\n
\n
\n ${this._lnb.markUp}\n ${this._appDownload.markUp}\n ${this._serviceList.markUp}\n ${this._banner.markUp}\n\n ${brtag}\n
\n
\n
\n
`;\n }\n}\n\nexport default LeftMain;\n","import AbsModule from '../common/AbsModule';\nimport * as Util from '../common/util';\n\nclass Shortcut extends AbsModule {\n constructor(_config) {\n super(_config.shortCut, _config.shortCut.isShow);\n this.dataBindList = [];\n }\n\n startSetting() {\n let shortcutUL = jQuery('#nc-cnb .ncc-shortcut-list');\n\n if (Util.isMobile) {\n jQuery('#nc-cnb .ncc-shortcut-item__link__mypage')\n .off('click')\n .on('click', e => {\n let url = jQuery(e.currentTarget).attr('href');\n window.open(url, 'myPage');\n return false;\n });\n\n shortcutUL.css({ 'overflow-x': 'auto' });\n } else {\n let shortListWidth = jQuery('#nc-cnb .ncc-shortcut-list .ncc-shortcut-item').length * 70;\n\n if (shortListWidth > 350) {\n jQuery('#nc-cnb .ncc-shortcut-btn--prev')\n .off('click')\n .on('click', e => {\n let nowScrLeft = shortcutUL.scrollLeft();\n shortcutUL.animate({ scrollLeft: nowScrLeft - 210 }, 250);\n });\n\n jQuery('#nc-cnb .ncc-shortcut-btn--next')\n .off('click')\n .on('click', e => {\n let nowScrLeft = shortcutUL.scrollLeft();\n shortcutUL.animate({ scrollLeft: nowScrLeft + 210 }, 250);\n });\n\n jQuery(window).on('resize.shortcut', e =>\n jQuery('#nc-cnb .ncc-shortcut-btn').toggle(shortListWidth > shortcutUL.width()),\n );\n jQuery(window).trigger('resize.shortcut');\n }\n }\n\n // function 타입 숏컷\n jQuery('.ncc-shortcut-item__link[data-func-name]').click(function() {\n const funcName = jQuery(this).data('func-name');\n const funcParams = jQuery(this).data('func-params');\n\n let $this = this;\n\n const func = funcName.split('.').reduce((acc, curVal) => {\n const obj = acc[curVal];\n if (typeof obj === 'object') {\n $this = obj;\n }\n return obj;\n }, window);\n\n if (jQuery.isFunction(func)) {\n func.call($this, funcParams);\n }\n return false;\n });\n }\n\n makeMarkup() {\n let listLeng = 0;\n let shortCutList = jQuery.extend(true, {}, this.moduleData);\n if (shortCutList.charHome) shortCutList.charHome = {};\n\n for (let prop in shortCutList) {\n let item = shortCutList[prop];\n if (item.isShow) listLeng++;\n }\n\n const nshopData = window.userData.nshop || window.userData.nShop || {};\n let nCoin = cnbL10NData.Shortcut.NCoin;\n let EnterCoupon = cnbL10NData.Shortcut.EnterCoupon;\n\n let nCoinItem = this.getShortCutItem('ncoin', nCoin, nshopData.nCoin || nshopData.ncoin, 999999, '{}');\n let enterCouponItem = this.getShortCutItem('entercoupon', EnterCoupon, nshopData.coupon, 99, '쿠폰 {}개');\n\n return `\n
`;\n }\n\n getShortCutItem(name, l10n, count, maxCount, _prefix) {\n let iconClass = name,\n value = l10n;\n if (count) {\n value = this.getShortCutNumber(count, maxCount);\n if (value === '' || parseInt(value, 10) === 0) {\n value = l10n;\n } else {\n iconClass += ' is-number';\n value = _prefix.replace('{}', value);\n }\n }\n\n return { iconClass, value };\n }\n\n getShortCutNumber(num, maxCount) {\n if (jQuery.isNumeric(num)) {\n num = num\n .toString()\n .replace(/^\\s\\s*/, '')\n .replace(/\\s\\s*$/, '');\n let chkNum = parseInt(num, 10),\n isFull = '';\n if (chkNum > maxCount) {\n num = maxCount.toString();\n isFull = '+';\n }\n return num.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',') + isFull;\n } else {\n return '';\n }\n }\n\n makeItem(_d, _className, _l10nName, _addData = false, _suffix = '') {\n if (typeof _d === 'undefined') return '';\n if (!_d.isShow) return '';\n if (_addData) this.dataBindList.push(_className + (_suffix ? '-' + _suffix : ''));\n\n // console.log(_d);\n const type = _d.iconType || _d.type;\n\n const link = `
`;\n const popup = ``;\n\n const funcParamsStr = JSON.stringify(_d.params);\n const button = ``;\n\n let aTag = '';\n switch (type) {\n case 'popup':\n aTag = popup;\n break;\n case 'function':\n aTag = button;\n break;\n default:\n aTag = link;\n }\n\n return `\n \n ${aTag}\n \n ${_l10nName}\n \n `;\n }\n\n /*createPopup(url, params) {\n let paramsStr = '';\n let keys = Object.keys(params);\n if (!keys.length) return '';\n let i, len = keys.length;\n for (i = 0; i < len; i++) {\n let key = keys[i];\n paramsStr += key + '=' + params[key];\n if(i < len-1) {\n paramsStr += ', ';\n }\n }\n return `window.open('${url}', '', '${paramsStr}').focus(); return false;`;\n }*/\n}\n\nexport default Shortcut;\n","import AbsModule from '../common/AbsModule';\nimport Shortcut from './Shortcut';\nimport uniqBy from 'lodash/uniqBy';\nimport filter from 'lodash/filter';\n\nclass UserInfo extends AbsModule {\n constructor(_config) {\n super(_config, _config.userData.isLogin);\n this._shortcut = new Shortcut(_config, _config.shortCut.isShow);\n }\n\n startSetting() {\n this._shortcut.start();\n\n jQuery('#nc-cnb .ncc-profile-links a.ncc-profile-logout')\n .off('click')\n .on('click', e => {\n let callbackFN = this.moduleData.logoutFN;\n if (typeof callbackFN === 'string' && typeof window[callbackFN] === 'function') {\n callbackFN = window[callbackFN];\n }\n if (typeof callbackFN === 'function') {\n callbackFN();\n }\n return false;\n });\n\n jQuery('#nc-cnb .ncc-profile-links a.ncc-profile-charchange')\n .off('click')\n .on('click', e => {\n let callbackFN = this.moduleData.charChangeFN;\n if (typeof callbackFN === 'string' && typeof window[callbackFN] === 'function') {\n callbackFN = window[callbackFN];\n }\n if (typeof callbackFN === 'function') {\n callbackFN();\n jQuery('.ncc-character-panel').addClass('is-active');\n }\n return false;\n });\n\n jQuery('.ncc-right-panel-close')\n .off('click')\n .on('click', () => {\n this.dim.openClose(false);\n return false;\n });\n }\n\n getCaseNum(accountType, state) {\n if (state) {\n return parseInt(state.case || 0, 10);\n }\n return -1;\n }\n\n makeMarkup() {\n /*\n 1 : 프로필 이미지 아래 상태 메세지 표시\n 2 ~ 6 : 프로필 이미지 나타나지 않고 그자리에 상태 메세지 표시\n 7 ~ : 프로필 이미지와 숏컷 사이에 상태 메세지 표시\n */\n const accountType = this.moduleData.userData.uesAccountType || this.moduleData.userData.useAccountType;\n const ncAccount = this.moduleData.userData.ncAccount,\n gameAccount = this.moduleData.userData.gameAccount;\n let userInfo = accountType === 'gameAccount' ? gameAccount : ncAccount;\n let userName = userInfo.name !== '' ? userInfo.name : ncAccount.name;\n let profileImage = userInfo.profileImage !== '' ? userInfo.profileImage : ncAccount.profileImage;\n let userInfoTarget = userInfo.target || '_self';\n\n let profileEle = '';\n let errorMsgEle = '';\n let useCharChangeMenu = this.moduleData.useCharChangeMenu;\n let showChangeCharMenu = false;\n\n let accountState = this.moduleData.userData.accountState;\n accountState = jQuery.isArray(accountState) ? accountState : [accountState];\n\n // accountState 값이 없을 경우 default값 지정\n if (accountState.length === 0) {\n accountState = [{ case: 0, msg: '' }];\n }\n\n const charHome = this.moduleData.shortCut && this.moduleData.shortCut.charHome;\n\n /*\n * 1. 대표 캐릭터 미 선택\n 2. 비 실명 확인\n 3. 보유 캐릭터 없음\n 4. L1, L2 페이스북 or 구글 로그인 / 비 실명 확인\n 5. L1, L2 페이스북 or 구글 로그인 / 실명 확인\n 6. 페이스북 or 구글 로그인 (L1, L2 외) / 비 실명 확인\n 7. 제재 (제재_고객센터, 제재_신고센터, 제재_1:1 문의의 3개 케이스를 제재_1:1 문의로 통일)\n 8. 제재-본인확인\n * */\n\n /*\n * 계정 상태 코드에 따른 화면 표시\n 1 : 프로필 이미지 아래 상태 메세지 표시\n 2 ~ 6 : 프로필 이미지 나타나지 않고 그자리에 상태 메세지 표시 (캐릭터 변경 버튼 표시안함)\n 7 ~ 8 : 프로필 이미지와 숏컷 사이에 상태 메세지 표시\n * */\n\n // case 그룹 생성 (동일한 case를 가진 데이터 합치기)\n const caseGroup = uniqBy(accountState, data => data.case);\n\n if (useCharChangeMenu) {\n showChangeCharMenu = true;\n\n // 2 ~ 6\n const noCharacter = filter(caseGroup, obj => {\n const cNum = this.getCaseNum(accountType, obj);\n return cNum > 1 && cNum < 7;\n });\n\n if (noCharacter.length) {\n showChangeCharMenu = false;\n }\n }\n\n const profileGroup = filter(caseGroup, obj => {\n const cNum = this.getCaseNum(accountType, obj);\n return cNum < 7;\n });\n\n const errorMsgGroup = filter(caseGroup, obj => {\n const cNum = this.getCaseNum(accountType, obj);\n return cNum >= 7;\n });\n\n // 마지막 인덱스만 사용\n const profileCaseData = profileGroup.pop();\n const errorMsgCaseData = errorMsgGroup.pop();\n\n // 프로필 영역\n const caseData = profileCaseData || errorMsgCaseData;\n profileEle = this.getProfileEle(\n accountType,\n caseData,\n userName,\n profileImage,\n userInfo,\n userInfoTarget,\n charHome,\n );\n\n // 에러 메시지 영역\n if (errorMsgCaseData) {\n errorMsgEle = this.getErrorMsgEle(accountType, errorMsgCaseData);\n }\n\n let showNcAccount = this.moduleData.showAccountName;\n let ncAccountInfo = '',\n isNcAccount = '',\n cnbType = this.moduleData.type || '';\n\n if (showNcAccount && accountType === 'gameAccount' && cnbType.toLowerCase() === 'a') {\n ncAccountInfo = `
`;\n isNcAccount = ' is-nc-account';\n }\n\n return `\n
\n
Close\n
\n
\n ${ncAccountInfo} \n
\n ${this._shortcut.markUp}\n
\n ${errorMsgEle}\n `;\n }\n\n getProfileEle(accountType, state, userName, profileImage, userInfo, userInfoTarget, charHome) {\n const caseNum = this.getCaseNum(accountType, state);\n let profileEle = '';\n let homeCls = accountType === 'gameAccount' ? ' ic-home' : '';\n /*const charHomeShow = (accountType === 'gameAccount') && charHome.isShow;\n ${charHomeShow ? `
` : ''}*/\n\n if (caseNum === 0 || (caseNum >= 7 && caseNum <= 12)) {\n // 프로필 영역 기본\n profileEle = `\n ${\n userInfo.url\n ? `\n
\n
\n \n `\n : `\n
\n

\n
\n `\n }\n
\n ${userName}\n ${accountType === 'gameAccount' ? this.subCharDataMaker(userInfo.subData) : ''}\n
\n `;\n }\n\n let errMsgHtml = state.msg;\n\n if (caseNum >= 2 && caseNum <= 6) {\n // 프로필 영역 에러 메세지\n profileEle = `\n
\n `;\n }\n\n if (caseNum === 1) {\n // 프로필 영역 캐릭터 미선택\n profileEle = `\n ${\n userInfo.url\n ? `\n
\n
\n \n `\n : `\n
\n

\n
\n `\n }\n
\n ${errMsgHtml}\n
\n `;\n }\n\n return profileEle;\n }\n\n getErrorMsgEle(accountType, state) {\n const caseNum = this.getCaseNum(accountType, state);\n let errMsgHtml = state.msg;\n return caseNum >= 7 && caseNum <= 12 ? `
${errMsgHtml}
` : '';\n }\n\n subCharDataMaker(_subdata) {\n const list = this.getSubData(_subdata);\n return list\n .map(\n (item, idx) => `\n
${item.value}\n `,\n )\n .join('\\n ');\n }\n\n getSubData(data) {\n if (typeof data === 'undefined') return [];\n let list = data.filter(it => {\n return it.value !== '' && it.value !== 'Lv';\n });\n return list;\n }\n}\n\nexport default UserInfo;\n","import Common from '../common/Common';\n\nclass NotiSetting {\n constructor(_config) {\n this.config = _config;\n this.com = Common.instance;\n this.container = jQuery('#notiSetting');\n this.isLoading = false;\n\n const { locale } = this.config.userData;\n const languages = ['ko-KR', 'en-US', 'zh-TW', 'ja-JP'];\n this.userLocale = languages.find(lang => {\n return lang.indexOf(locale) !== -1;\n });\n\n this.isRc = /(rc\\.)/i.test(location.href) ? 'rc.' : '';\n this.isRc = /(rc\\-)/i.test(location.href) ? 'rc-' : this.isRc;\n this.isRc = /(rc2\\-)/i.test(location.href) ? 'rc-' : this.isRc;\n\n let thisSiteNum = { lineage: '27', bns: '24', aion: '26', rk: '178' };\n this.prior = !!thisSiteNum[this.config.userData.site] ? thisSiteNum[this.config.userData.site] : '';\n\n let nowDomain = /(asia\\.nc\\.com)/i.test(location.href) ? 'asia.nc.com' : 'noti.plaync.com';\n this.api = {\n list: location.protocol + '//' + this.isRc + nowDomain + '/noti/api/common/getReceiveSetting.jsonp',\n reject:\n location.protocol + '//' + this.isRc + nowDomain + '/noti/api/common/updateReceiveSetting.jsonp',\n };\n\n if (this.com.env === 'opdev') {\n this.api = {\n list: 'http://ui-static.korea.ncsoft.corp/uikit/cnb/data/notisettingdummydata.json',\n reject: 'http://ui-static.korea.ncsoft.corp/uikit/cnb/data/notisettingdummydata2.json',\n };\n }\n }\n\n\n start() {\n\n\n jQuery.ajax({\n url: this.api.list,\n data: { priorMainCategories: this.prior, language: this.userLocale },\n dataType: 'jsonp',\n type: 'GET',\n jsonpCallback: 'callback',\n success: _data => {\n if (_data.result.returnMessage === 'SUCCESS') {\n let temp =\n this.tmplHeader(_data.result.notiResult) +\n this.tmplCategoryList(_data.result.notiResult.mainCategoryList) +\n this.tmplBtns();\n this.container.html(temp);\n if (!_data.result.notiResult.receive) this.container.find('dl').hide();\n\n this.addEvents();\n if (window.ncNotice) {\n window.ncNotice.$dispatcher.trigger('load-complete');\n }\n }\n },\n beforeSend: () => {},\n complete: () => {},\n error: (xhr, status) => {},\n });\n }\n\n addEvents() {\n jQuery('#notiSetting .wrap_btns .btnApply')\n .off('click')\n .on('click', e => this.apply());\n\n jQuery('#notiSetting .wrap_btns .btnCancel')\n .off('click')\n .on('click', e => {\n if (window.ncNotice) {\n jQuery('#notiSetting').hide();\n jQuery('#notiList').show();\n window.ncNotice.start();\n }\n });\n\n jQuery('#notiSetting dl dt input:checkbox')\n .off('change')\n .on('change', e => {\n let tNode = jQuery(e.target);\n tNode\n .parents('dl')\n .eq(0)\n .toggleClass('checked', tNode.is(':checked'));\n\n window.ncNotice.$dispatcher.trigger('change-checked');\n });\n\n jQuery('#notiSetting header input:checkbox')\n .off('change')\n .on('change', e => {\n this.container.find('dl').toggle(jQuery(e.target).is(':checked'));\n\n window.ncNotice.$dispatcher.trigger('change-checked');\n });\n }\n\n apply() {\n if (this.isLoading) return;\n let list = '';\n let comma = ',';\n let elList = jQuery('#notiSetting input:checkbox');\n elList.each((idx, it) => {\n if (!jQuery(it).is(':checked')) {\n list += it.id + (idx == elList.length - 1 ? '' : comma);\n }\n });\n\n jQuery.ajax({\n url: this.api.reject + '?rejectedCategories=' + list,\n data: { language: this.userLocale },\n dataType: 'jsonp',\n type: 'GET',\n jsonpCallback: 'callback',\n success: _data => {\n if (typeof _data.result !== 'undefined' && _data.result.returnMessage === 'SUCCESS') {\n this.tmplSettingCompleteMsg(_data);\n } else {\n this.tmplSettingErrorMsg();\n }\n },\n beforeSend: () => {\n this.isLoading = true;\n },\n complete: () => {\n this.isLoading = false;\n },\n error: (xhr, status) => {\n this.tmplSettingErrorMsg();\n },\n });\n }\n\n tmplHeader(_data) {\n let temp =\n '
';\n return temp;\n }\n\n tmplCategoryList(_data) {\n let temp = '';\n for (let i = 0; i < _data.length; i++) {\n temp += this.tmplCategory(_data[i]);\n }\n return temp;\n }\n\n tmplCategory(_data) {\n let items = '';\n for (let i = 0; i < _data.subCategoryList.length; i++) {\n items += this.tmplItem(_data.subCategoryList[i]);\n }\n\n let temp =\n '
' +\n '- ' +\n ' ' +\n '' +\n '
' +\n items +\n '
';\n return temp;\n }\n\n tmplItem(_data) {\n let temp =\n '
' +\n ' ' +\n '' +\n '';\n return temp;\n }\n\n tmplBtns() {\n let temp =\n '
' +\n ' ' +\n '' +\n '
';\n return temp;\n }\n\n tmplSettingCompleteMsg(_data) {\n let dat = _data.result.notiResult.serverDateTime;\n let dateStr =\n dat.substr(0, 4) +\n notiL10NData.Year +\n ' ' +\n dat.substr(4, 2) +\n notiL10NData.Month +\n ' ' +\n dat.substr(6, 2) +\n notiL10NData.Day +\n ',\\n';\n let str = dateStr + notiL10NData.NotiSettingsChanged;\n\n let recList = _data.result.notiResult.adReceiveList;\n let rejList = _data.result.notiResult.adRejectList;\n let recStr = notiL10NData.AgreedToReceiveAdvertisements;\n let rejStr = notiL10NData.WithdrawnFromAgreementReceiveAdvertisements;\n let recTmp = '';\n let rejTmp = '';\n\n if (recList.length > 0) {\n recTmp += '\\n\\n';\n for (let i = 0; i < recList.length; i++) {\n let item = recList[i];\n recTmp += (i == 0 ? '' : '/') + item.mainCategory + '-' + item.subCategory;\n }\n recTmp += recStr;\n }\n\n if (rejList.length > 0) {\n rejTmp += '\\n\\n';\n for (let i = 0; i < rejList.length; i++) {\n let item = rejList[i];\n rejTmp += (i == 0 ? '' : '/') + item.mainCategory + '-' + item.subCategory;\n }\n rejTmp += rejStr;\n }\n\n str += recTmp + rejTmp;\n\n alert(str);\n if (window.ncNotice) {\n jQuery('#notiSetting').hide();\n jQuery('#notiList').show();\n window.ncNotice.start();\n }\n }\n\n tmplSettingErrorMsg() {\n let str = notiL10NData.ProcessisDelayed;\n alert(str);\n }\n}\n\nexport default NotiSetting;\n","import AbsModule from '../common/AbsModule';\nimport NotiSetting from './NotiSetting';\nimport api from '../notice/notiApi';\n\nclass Noti extends AbsModule {\n startSetting() {\n this._notisetting = new NotiSetting(this.moduleData);\n\n jQuery('#nc-cnb .ncc-noti-list .wrap_btns button.btnSetting')\n .off('click')\n .on('click', () => {\n jQuery('#notiList').hide();\n jQuery('#notiSetting').show();\n this._notisetting.start();\n });\n\n if (this.moduleData.userData.isLogin) {\n this.loadNotiCount();\n }\n }\n\n loadNotiCount() {\n const apiData = window.notiDummyData || api;\n\n jQuery.ajax({\n url: apiData.count,\n dataType: 'jsonp',\n type: 'GET',\n jsonpCallback: 'callback',\n data: { 'targetCategory[]': 'GNB_NOTI' },\n success: _data => {\n if (_data.result.returnMessage == 'SUCCESS') {\n let countNum = parseInt(_data.result.notiResult.countList[0].notiCount);\n let isShow = countNum > 0;\n\n if (isShow) {\n let num = countNum > 99 ? '99+' : countNum;\n jQuery('#nc-cnb .ncc-login .ncc-login--info__noti span')\n .text(num)\n .css('display', 'inline-block');\n\n jQuery('#nc-cnb .ncc-noti-tab a span')\n .text(num)\n .css('display', 'inline-block');\n jQuery('.ncc-login--user-btn .noti-alarm-count')\n .text(num)\n .css('display', 'inline-block');\n } else {\n this.notiCountNumHide();\n }\n } else {\n this.notiCountNumHide();\n }\n },\n beforeSend: () => {},\n complete: () => {},\n error: () => {\n this.notiCountNumHide();\n },\n });\n }\n\n notiCountNumHide() {\n jQuery('#nc-cnb .ncc-login .ncc-login--info__noti span')\n .text(0)\n .hide();\n\n jQuery('#nc-cnb .ncc-noti-tab a span')\n .text(0)\n .hide();\n jQuery('.ncc-login--user-btn .noti-alarm-count').hide();\n }\n\n makeMarkup() {\n return `\n
\n
\n
\n
\n
\n
\n
\n `;\n }\n}\n\nexport default Noti;\n","import AbsModule from '../common/AbsModule';\nimport UserInfo from './UserInfo';\nimport Noti from './Noti';\nimport { isMobile } from '../common/util';\n\nclass RightMain extends AbsModule {\n constructor(_config) {\n super(_config, _config.userData.isLogin);\n\n this._userInfo = new UserInfo(_config);\n this._noti = new Noti(_config);\n }\n\n startSetting() {\n this._userInfo.start();\n this._noti.start();\n\n window.ncNotice.$dispatcher.on('load-complete change-checked', () => {\n // console.log('notice!!');\n this.createIScroll();\n });\n\n const $panel = jQuery('.ncc-right-panel');\n if ($panel.length) {\n const panel = $panel[0];\n const stopEvtAction = e => {\n e.preventDefault();\n };\n panel.addEventListener('touchmove', stopEvtAction, { passive: false });\n }\n }\n\n createIScroll() {\n if (this.iScroll) {\n this.iScroll.refresh();\n } else {\n const isMo = isMobile;\n this.iScroll = new IScroll('.ncc-right-panel-wrap', {\n scrollbars: true,\n mouseWheel: true,\n interactiveScrollbars: true,\n shrinkScrollbars: 'scale',\n disableMouse: !isMo,\n disablePointer: !isMo,\n fadeScrollbars: true,\n // preventDefault: false,\n preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|A|LI|SPAN|IMG|STRONG)$/ },\n });\n }\n }\n\n destroy() {\n if (this.iScroll) {\n this.iScroll.destroy();\n this.iScroll = null;\n }\n }\n\n makeMarkup() {\n let brtag = `
`;\n if($('body').hasClass('ANDROID')){\n brtag = `
`;\n }\n return `\n\t\t
\n\t\t
\n
\n ${this._userInfo.markUp}\n
\n
\n ${this._noti.markUp}\n\n ${brtag}\n
\n
\n\t\t
\n\t\t
`;\n }\n}\n\nexport default RightMain;\n","import AbsModule from '../common/AbsModule';\n\nclass Character extends AbsModule {\n startSetting() {\n jQuery('#nc-cnb').on('click', '.ncc-character-panel .ncc-character-panel-close', e => {\n jQuery('.ncc-character-panel').removeClass('is-active');\n return false;\n });\n }\n\n makeMarkup() {\n return `\n
`;\n }\n}\n\nexport default Character;\n","import isString from 'lodash/isString';\n\nimport './lib/iscroll';\nimport './common/notiList';\n\nimport * as Util from './common/util';\nimport Header from './header/HeaderMain';\nimport Left from './left/LeftMain';\nimport Right from './right/RightMain';\nimport Character from './character/Character';\nimport Dimmed from './common/Dimmed';\nimport Common, { CNB_TYPE } from './common/Common';\nimport tmpl from './notice/notiTemplate';\n\n/*\n * 경고!\n * babel core-js 3으로 트랜스파일.\n * ie에서 stackoverflow 간혹 발생. (반드시 ie에서 확인 후 배포)\n * playnclib 충돌을 피해 jQuery alias 사용\n * */\nclass App {\n constructor() {\n this.con = jQuery('#nc-cnb');\n this.orgClass = this.con.attr('class');\n this.com = Common.instance;\n this.dim = Dimmed.instance;\n this.com.init();\n\n this.deviceName = Util.isMobile ? 'mobile' : 'pc';\n this.browser = (Util.nowBrowser || '').toLowerCase();\n }\n\n start(_config) {\n this.startconfig = _config;\n //document.cookie = 'visitedGame=; expires=Thu, 01 Jan 1999 00:00:10 GMT;';\n\n this.destroy();\n if (typeof window.userData !== 'object') window.userData = { isLogin: false, locale: 'ko-KR' };\n\n // cnbData\n this.loadStartCnbData(window.userData.locale.slice(0, 2));\n /* jQuery.ajax({\n dataType: 'script',\n url: this.com.staticHost + '/uikit/cnb/data/cnbData-' + window.userData.locale.slice(0, 2) + '.js',\n success: () => {\n // nshop coupon\n const useNshopInstance = window.nshop && window.nshop.popup; // 이미 사용중\n if (!useNshopInstance) {\n jQuery.ajax({\n dataType: 'script',\n url: this.com.staticHost + '/nshop/common/popup/dist/js/popup-0.0.4-min.js',\n success: () => {},\n });\n }\n this.setting(_config);\n },\n }); */\n\n }\n\n loadStartCnbData(_loc){\n jQuery.ajax({ \n dataType: 'script',\n url: this.com.staticHost + '/uikit/cnb/data/cnbData-'+_loc+'.js',\n })\n .done((_d)=> {\n this.loadCompleteCnbData();\n })\n .fail((_d)=> {\n console.log( 'err :', _d );\n this.loadStartCnbData('en');\n });\n }\n\n loadCompleteCnbData(){\n // nshop coupon\n const useNshopInstance = window.nshop && window.nshop.popup; // 이미 사용중\n if (!useNshopInstance) {\n jQuery.ajax({\n dataType: 'script',\n url: this.com.staticHost + '/nshop/common/popup/dist/js/popup-0.0.4-min.js',\n success: () => {},\n });\n }\n\n this.setting(this.startconfig);\n }\n\n destroy() {\n if (this.leftP) this.leftP.destroy();\n if (this.rightP) this.rightP.destroy();\n }\n\n setting(_config) {\n this.com.config = _config;\n\n this.con.attr('data-ncc-device', this.deviceName);\n\n if (this.com.env !== 'live') {\n this.con.attr('data-ncc-browser', this.browser);\n }\n\n this.con.attr('class', this.orgClass);\n this.con.addClass(this.com.theme.classes.theme);\n\n let isUserMenu = !(typeof this.com.config.useLoginMenu === 'undefined'\n ? true\n : this.com.config.useLoginMenu);\n if (isUserMenu) this.con.attr('data-disable-menu', '');\n\n if (this.com.config.type) this.con.attr('data-cnb-type', this.com.config.type.toLowerCase());\n if (this.com.config.theme && this.com.config.theme.colorScheme) {\n let scheme = this.com.config.theme.colorScheme;\n if (!isString(scheme)) {\n scheme = scheme.name;\n }\n this.con.attr('data-theme', scheme);\n }\n\n // iphoneX && chrome 체크!\n if (Util.isiPhoneX && navigator.userAgent.match('CriOS')) {\n this.con.addClass('iphonex-chrome');\n }\n\n if (this.com.config.type === CNB_TYPE.NONE) {\n this.setDefaultType();\n } else {\n let setCnbUI = this['set' + this.com.config.type + 'Type'];\n if (typeof setCnbUI === 'function') {\n setCnbUI.call(this);\n }\n }\n }\n\n resetSearchBar() {\n if (this.header) {\n this.header._search.hideSearchField();\n }\n }\n\n setDefaultType() {\n let header = new Header(this.com.config);\n let leftP = new Left(this.com.config);\n let rightP = new Right(this.com.config);\n let characterP = new Character(this.com.config, this.com.config.useCharChangeMenu);\n\n this.con.html(header.markUp + leftP.markUp + rightP.markUp + characterP.markUp);\n this.dim.init();\n\n header.start();\n leftP.start();\n rightP.start();\n characterP.start();\n\n this.leftP = leftP;\n this.rightP = rightP;\n this.header = header;\n }\n\n /*\n A : 게임 사이트\n */\n setAType() {\n this.setDefaultType();\n }\n\n /*\n B : 게임 프로모션, 업데이트 연대기 사이트\n - 서비스 전체보기, BI, 로그인 / 로그아웃\n */\n setBType() {\n /*this.con.addClass('nc-cnb--simple');\n let header = new Header( this.com.config );\n let leftP = new Left( this.com.config );\n\n this.con.html( header.markUp + leftP.markUp );\n this.dim.init();\n\n header.start();\n leftP.start();\n\n this.leftP = leftP;*/\n this.setDefaultType();\n }\n\n /*\n C : 회원 사이트 (마이페이지, 고객센터, N샵)\n */\n setCType() {\n this.setDefaultType();\n }\n\n /*\n D : 기타 사이트 (메인, 약관/정책, 공지사항, 장기 미이용 복귀 센터, 게임시간선택제)\n */\n setDType() {\n this.setDefaultType();\n }\n\n openCharacterPan() {\n this.dim.openClose(true, 'right');\n if (typeof window.ncNotice === 'object') window.ncNotice.start();\n jQuery('.ncc-character-panel').addClass('is-active');\n jQuery('#nc-cnb .ncc-profile-links a.ncc-profile-charchange').trigger('click');\n }\n\n message(msg) {\n jQuery(tmpl.alertMessage(msg))\n .modal()\n .on('hide.modal', () => {\n jQuery('#notice_alert').remove();\n });\n }\n}\n\nwindow.cnb = new App();\n"],"sourceRoot":""}