본문으로 이동
주 메뉴
주 메뉴
사이드바로 이동
숨기기
둘러보기
대문
도움말
최근 바뀜
게임 목록
임의의 게임으로
Top 20
청사진
커뮤니티
오락실
토론란
발전소
추천 게임
게임제작도움방
자매 프로젝트
리버티책
오사인덱스
진실위키
큰숲백과
위키연합회의장
연합회의장
사이트 개발 서버
개발 서버
리버티게임
검색
검색
보이기
계정 만들기
로그인
개인 도구
계정 만들기
로그인
로그아웃한 편집자를 위한 문서
더 알아보기
기여
토론
미디어위키:Gadget-PluginCore.js 문서 원본 보기
메시지
토론
English
읽기
원본 보기
역사 보기
도구
도구
사이드바로 이동
숨기기
동작
읽기
원본 보기
역사 보기
새로 고침
일반
여기를 가리키는 문서
가리키는 글의 최근 바뀜
특수 문서 목록
문서 정보
축약된 URL 얻기
보이기
사이드바로 이동
숨기기
←
미디어위키:Gadget-PluginCore.js
문서 편집 권한이 없습니다. 다음 이유를 확인해주세요:
이 문서는 소프트웨어 인터페이스에 쓰이는 문서로, 부정 행위를 막기 위해 보호되어 있습니다.
이 문서는
관리자
만이 수정할 수 있습니다. 내용의 변경이 필요하다면
관리자 요청
에 편집 요청을 남겨 주세요.
모든 방문자에게 영향을 미칠 수 있기 때문에 이 자바스크립트 문서의 편집 권한이 없습니다.
문서의 원본을 보거나 복사할 수 있습니다.
/** [[틀:플러그인]]을 사용 가능하게 해 줍니다. 사용자의 허락을 맡고 사용자의 commonjs 편집을 허가 할 수 있는 문서입니다. * 작성자: [[사용자:BANIP|BANIP]] * - [[백괴게임:관리자 요청/2018년 1월]]에서 BANIP님 요청으로 퍼왔습니다. * - 2023.06.04 2.0.0 전체적인 소스 리팩토링/MediaWikiAPI의 의존성 삭제 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 6월 4일 (일) 13:52 (KST) */ // 페이지 로드 후 실행 $(function () { // 구현필요 var repo = { PAGE_MISSING: 'The page does not exist.', api: new mw.Api(), getRawDocument: function (title) { return new Promise(function (resolve, reject) { repo.api .get({ action: 'query', prop: 'revisions', rvprop: 'content', titles: title, formatversion: 2, }) .then( function (data) { var page = data.query.pages[0]; if (page.missing) { reject(repo.PAGE_MISSING); } else { resolve(page.revisions[0].content); } }, function (e) { reject(e); } ); }); }, changeDocument: function (title, text, summary, otherOptions) { return new Promise(function (resolve, reject) { repo.api .postWithEditToken( Object.assign( { action: 'edit', title: title, text: text, summary: summary, //nocreate: true, }, otherOptions ) ) .then( function (data) { if (data.edit.result === 'Success') resolve(data); else reject(data); }, function (e) { reject(e); } ); }); }, getDocument: function (title) { return new Promise(function (resolve, reject) { repo.api .get({ action: 'parse', page: title, formatversion: 2, }) .then( function (data) { resolve(data.parse.text); }, function (e) { reject(e); } ); }); }, getPluginMetadata: function (page) { var revisionPromise = repo.api.get({ action: 'query', prop: 'revisions', rvlimit: 1, rvprop: 'timestamp|user|comment', titles: page, formatversion: 2, }); var parsedPagePromise = repo.api.get({ action: 'parse', page: page, formatversion: 2, }); return Promise.all([revisionPromise, parsedPagePromise]).then(function ( results ) { var revisionResponse = results[0]; var parsedPageResponse = results[1]; var pages = revisionResponse.query.pages; var pageId = Object.keys(pages)[0]; var revision = pages[pageId].revisions[0]; var parsedContent = parsedPageResponse.parse.text; return { author: revision.user, timestamp: revision.timestamp, comment: revision.comment, code: $(parsedContent).find('pre.script').text(), }; }); }, }; // 플러그인이 비어있는지 확인 function isPluginsEmpty(plugins) { return Object.keys(plugins).length === 0; } //플러그인의 모든 키 순회 function forEach(object, callback) { for (var key in object) { var variable = object[key]; callback(variable, key); } } var getPlugin = { // 문서에서 사용하는 플러그인들을 체크합니다. use-script클래스를 가진 모든 돔 요소를 조사하고 // 그 돔에 내장된 플러그인 데이터를 docPlugins에 추가합니다. document: function () { // 현재 문서에 사용되는 플러그인들의 데이터를 docPlugins에 추가합니다. return $('.use-script') .toArray() .map(function (el) { var $this = $(el); return { name: $this.attr('data-name'), // 플러그인 이름 descript: $this.attr('data-descript'), // 플러그인 내용 version: $this.attr('data-version'), // 플러그인 이름 local: $this.attr('data-local') === 'true', // 즉시 실행 여부 creat: $this.attr('data-creat'), // 플러그인 작성자 이름 state: $this.attr('data-state'), link: $this.attr('data-link'), executable: $this.attr('data-executable') === 'true', }; }); }, user: function (commonjs) { var userplugins = []; // plugins.---가 있는지 체크하는 정규식 var pluginreg = /JSON \=\> ([\S]+) = (\{.*\})/g; var nameMatch = pluginreg.exec(commonjs); while (nameMatch) { userplugins.push(JSON.parse(nameMatch[2])); nameMatch = pluginreg.exec(commonjs); } return userplugins; }, }; // 문서의 서브타이틀을 플러그인들의 이름으로 설정합니다. function setSubtitleByPlugins(plugins) { // 서브타이틀에 현재 가동중인 플러그인들의 이름을 추가합니다. var pluginNames = plugins.map(function (plugin) { return plugin.name; }); var subTitle = ' ' + pluginNames.join(', ') + ' 플러그인 가동중'; $('#siteSub').text(function (i, v) { return v + subTitle; }); } // 플러그인을 사용자문서에 추가합니다. function getUpdatedCommonjs(plugins, commonjs, pluginMeta) { function getPluginCode(plugin) { function entityDecode(doc) { return $('<script></script>').html(doc).text(); } function getDocHead(plugin) { var docHead = ''; var toJSONPlugin = Object.assign({}, plugin); toJSONPlugin.code = undefined; toJSONPlugin.link = undefined; docHead += '\n'; docHead += '\n/** 플러그인 ' + plugin.name + '***************************\n'; docHead += '* ' + plugin.descript + '\n'; docHead += '* 버전 => ' + plugin.version + '\n'; docHead += '* 작성자 : [[사용자:' + plugin.creat + '|' + plugin.creat + ']] \n'; docHead += '* JSON => ' + plugin.name + ' = ' + JSON.stringify(toJSONPlugin) + '; \n'; docHead += '*/ \n'; docHead += 'function plugin_' + plugin.name + '(){\n'; if (plugin.local) docHead += ' if($("[data-name=\'' + plugin.name + '\']").length >= 1){\n'; return docHead; } function getDocFoot(plugin) { var docFoot = ''; if (plugin.local) docFoot += '\n }\n'; docFoot += '\n}\n'; if (plugin.executable) docFoot += '$( plugin_' + plugin.name + ' );\n'; docFoot += '/* ' + plugin.name + ' 끝 */\n\n'; return docFoot; } var docHead = getDocHead(plugin); var docFoot = getDocFoot(plugin); return entityDecode(docHead + pluginMeta[plugin.name].code + docFoot); } //commonjs에서 특정 플러그인 제거 function removePluginByDoc(pluginTitle, commonjs) { var reg = new RegExp( '\\/\\*\\* 플러그인 ' + pluginTitle + '([\\s\\S]*)\\/\\* ' + pluginTitle + ' 끝 \\*\\/', 'g' ); commonjs = commonjs.replace(reg, ''); return commonjs; } plugins.forEach(function (plugin) { commonjs = removePluginByDoc(plugin.name, commonjs); commonjs += getPluginCode(plugin); }); return commonjs; } // 플러그인 안내 템플릿을 반환합니다. function getInstallPagePromise( userPlugins, uninstalledPlugins, unupdatedPlugins, pluginMeta ) { function getPluginCard($template, plugin, status) { var pluginName = plugin.name; var $box = $template .find('.cloneable.p-box') .clone() .removeClass('cloneable'); var code = pluginMeta[pluginName].code; $box.find('.p-status').text(status); $box.find('.p-code').text(code.replace(/\s{1,}$/, '')); $box.find('.p-name').text(pluginName); $box.find('.p-descript').text(plugin.descript); if (status == '버전업') { var prevVersion = userPlugins.find(function (userPlugin) { return userPlugin.name == pluginName; }).version; $box.find('.p-version').text(prevVersion + ' => ' + plugin.version); } else { $box.find('.p-version').text(plugin.version); } $box.find('.p-local').text( plugin.local == true ? '일부 문서만' : '문서 전체' ); $box.find('.p-creat').text(pluginMeta[pluginName].author); $box.find('.p-last').text(pluginMeta[pluginName].timestamp); $box.find('.p-comment').text(pluginMeta[pluginName].comment); return $box; } return repo.getDocument('틀:플러그인/setup').then(function (templateRaw) { var $template = $(templateRaw); var allPlugins = uninstalledPlugins.concat(unupdatedPlugins); allPlugins.forEach(function (plugin) { var status = uninstalledPlugins.includes(plugin) ? '설치' : '버전업'; var pluginCard = getPluginCard($template, plugin, status); $template.find('.box-article').append(pluginCard); }); return $template; }); } // 플러그인 설치 관련 로직 (function () { var commonjsPath = '사용자:' + mw.config.get('wgUserName') + '/common.js'; // 사용자의 commonjs의 경로를 획득합니다. var docPlugins = getPlugin.document(); // 문서에서 사용하는 플러그인들을 체크합니다. if (Object.keys(docPlugins).length === 0) return; // 문서에서 사용하는 플러그인이 없으면 종료합니다. setSubtitleByPlugins(docPlugins); // 문서의 서브타이틀을 문서에서 사용중인 플러그인들의 이름으로 설정합니다. repo.getRawDocument(commonjsPath) // 사용자의 commonjs의 문서를 획득합니다. .then( function (commonjsRaw) { var userPlugins = getPlugin.user(commonjsRaw); // 사용자가 가지고 있는 플러그인들을 체크합니다. var uninstalledPlugins = docPlugins.filter(function (plugin) { return !userPlugins.some(function (userPlugin) { return userPlugin.name === plugin.name; }); }); // 사용자가 가지고 있지 않은 플러그인들을 체크합니다. var unupdatedPlugins = docPlugins.filter(function (plugin) { return userPlugins.some(function (userPlugin) { return ( userPlugin.name === plugin.name && userPlugin.version !== plugin.version ); }); }); // 사용자가 가지고 있는 플러그인들 중 버전이 다른 플러그인들을 체크합니다. return { commonjsRaw: commonjsRaw, userPlugins: userPlugins, uninstalledPlugins: uninstalledPlugins, unupdatedPlugins: unupdatedPlugins, }; }, function (err) { // 사용자 common.js 문서가 없는 경우 if (err === repo.PAGE_MISSING) { // 모든 플러그인을 설치합니다. return { commonjsRaw: '', userPlugins: [], uninstalledPlugins: docPlugins, unupdatedPlugins: [], }; } else throw err; } ) .then(function (results) { var commonjsRaw = results.commonjsRaw; var userPlugins = results.userPlugins; var uninstalledPlugins = results.uninstalledPlugins; var unupdatedPlugins = results.unupdatedPlugins; // 추가 플러그인 설치가 필요하지 않은 경우 로직 종료 if ( isPluginsEmpty(uninstalledPlugins) && isPluginsEmpty(unupdatedPlugins) ) return; // 설치가 필요한 플러그인들의 이름을 문자열로 반환합니다. var needPluginNames = uninstalledPlugins .concat(unupdatedPlugins) .map(function (plugin) { return plugin.name; }) .join(', '); // 플러그인 개발자/코드/마지막 수정일 등 획득, 설치버튼 클릭 시 즉시 설치 가능하도록 미리 Promise를 생성 var pluginMetaPromise = Promise.all( uninstalledPlugins .concat(unupdatedPlugins) .map(function (plugin) { return Promise.all([ plugin.name, repo.getPluginMetadata(plugin.state), ]); }) ) .then(function (pluginMeta) { return Object.fromEntries(pluginMeta); }) .catch(function () { alert( '플러그인 정보를 불러오는데 실패했습니다. 페이지를 리로드 해주세요.' ); }); // 플러그인 리스트 수집 끝나면 플러그인 안내 템플릿을 반환하는 Promise를 생성 var installPagePromise = pluginMetaPromise .then(function (pluginMeta) { return getInstallPagePromise( userPlugins, uninstalledPlugins, unupdatedPlugins, pluginMeta ); }) .catch(function () { alert( '플러그인 설치 페이지를 불러오는데 실패했습니다. 페이지를 리로드 해주세요.' ); }); // 플러그인 설치 버튼 클릭 이벤트 핸들러 var setInstallPage = function (pluginMeta) { function install( commonjsPath, commonjs, needPluginNames, otherOptions ) { return repo .changeDocument( commonjsPath, commonjs, '플러그인 ' + needPluginNames + '설치', otherOptions ) .then(function () { location.reload(); }) .catch(function (e) { if (typeof e === 'object' && e.edit.captcha) { var captchaId = e.edit.captcha.id; var captchaAnswer = prompt( '플러그인을 설치하려면 다음 문제를 해결하십시오: \n' + e.edit.captcha.question ); if(captchaAnswer === null) { // 사용자 취소 시 $('.install-button').text('설치하기'); return; } return install( commonjsPath, commonjs, needPluginNames, { captchaid: captchaId, captchaword: captchaAnswer, } ); } alert( '플러그인 설치에 실패했습니다. 다시 시도해주세요.' ); console.error(e); $('.install-button').text('설치하기'); }); } return installPagePromise.then(function ($installPage) { $installPage .find('.install-button') .on('click', function () { $('.install-button').text('설치중..'); //$('.install-button').off('click'); var commonjs = getUpdatedCommonjs( uninstalledPlugins.concat(unupdatedPlugins), commonjsRaw, pluginMeta ); install(commonjsPath, commonjs, needPluginNames); }); var $document = $('#mw-content-text'); $document.html($installPage); }); }; var $loadCodeLink = $('.plugin-install'); // 플러그인 설치 필요 틀이 있는 페이지인 경우 if ($loadCodeLink.length >= 1) { $loadCodeLink.eq(0).closest('.ambox').show(); // 플러그인 설치 필요 틀을 보여줍니다. $('.plugin-name').eq(0).text(needPluginNames); // 필요한 플러그인들의 이름을 표시합니다. $loadCodeLink.on('click', function () { // 클릭한 버튼 이벤트 끄고 로딩중메세지 표시 $loadCodeLink.off('click'); $loadCodeLink.text( '필요한 플러그인 데이터를 가져오고 있습니다...' ); pluginMetaPromise.then(setInstallPage); }); // 플러그인 설치 버튼을 클릭하면 플러그인 체크 로직을 실행합니다. } else { pluginMetaPromise.then(setInstallPage); } }); })(); });
미디어위키:Gadget-PluginCore.js
문서로 돌아갑니다.