미디어위키:Gadget-PluginX.js

리버티게임(개발), 모두가 만들어가는 자유로운 게임
>BANIP님의 2023년 7월 9일 (일) 23:20 판 (PluginX 버전업)
둘러보기로 이동 검색으로 이동

참고: 설정을 저장한 후에 바뀐 점을 확인하기 위해서는 브라우저의 캐시를 새로 고쳐야 합니다.

  • 파이어폭스 / 사파리: Shift 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5 또는 Ctrl-R을 입력 (Mac에서는 ⌘-R)
  • 구글 크롬: Ctrl-Shift-R키를 입력 (Mac에서는 ⌘-Shift-R)
  • 인터넷 익스플로러 / 엣지: Ctrl 키를 누르면서 새로 고침을 클릭하거나, Ctrl-F5를 입력.
  • 오페라: Ctrl-F5를 입력.
/**
 * pluginX Core
 * pluginX 시스템이 제대로 돌아가게 해 줍니다.
 * 작성자: [[사용자:Bd3076|Bd3076]]
 * v2.0.0 전체수정 --[[사용자:BANIP|BANIP]] ([[사용자토론:BANIP|토론]]) 2023년 7월 9일 (일) 23:20 (KST)
*/
function pluginXCore() {
    //pluginX를 문서에서 사용하지 않으면 종료
    if ($("#bodyContent .pluginx-script-wrapper").length == 0) return;
    
	// 플러그인 목록 반환
    var getPluginList = function() {
		var pluginItems = [];
		/// 현재 문서 페이지에서 필요한 플러그인 수집
		$("#bodyContent .pluginx-script-wrapper").each(function() {
			var $this = $(this);
			var url = $this.data('url');
			// 이미 추가된 플러그인이면 추가하지 않음
			if (pluginItems.find(function(item) { return item.url == url; })) return;
			// 플러그인 목록에 추가
			pluginItems.push({
				url: url,
				name: $this.data('name'),
				creator: $this.data('creator'),
				doc: $this.data('doc'),
				revid: $this.data('rev-id'),
				script: $this.text(),
				revTimestamp: $this.data('rev-timestamp'),
				revUser: $this.data('rev-user'),
			});
		});
		return pluginItems;
	}
	


	var setting = {
		storageKey: "gadget-pluginx",
		get: function(){
			// trusted: {doc:string, revid, revUser:string, revTimestamp:string, }[]
			return JSON.parse(localStorage.getItem(setting.storageKey) || '{"trusted": []}');
		},
		getTrustedItems: function(){
			return setting.get().trusted;
		},
		getTrustedItemByDoc: function(doc){
			return setting.getTrustedItems().find(function(item){ return item.doc == doc; });
		},
		set: function(data){
			localStorage.setItem(setting.storageKey, JSON.stringify(data));
		},
		setTrustedItems: function(items){
			var data = setting.get();
			items.forEach(function(item){
				var itemForPush = {
					revid : item.revid,
					revTimestamp : item.revTimestamp, 
					revUser : item.revUser,
					doc : item.doc,
				};
				var index = data.trusted.findIndex(function(trustedItem){ return trustedItem.doc == item.doc; });
				if(index == -1){
					data.trusted.push(itemForPush);
				}else{
					data.trusted[index] = itemForPush;
				}
			});

			setting.set(data);
		}
	};
    
	var installPopup = {
		// 플러그인 인스톨 페이지 가져오기
		_getPopupElement:function(option){
			option = option || {};
			resolveCallback = option.resolveCallback || function(){};
			rejectCallback = option.rejectCallback || function(){};
			if(installPopup._$popupWrapper === undefined){
				// 설치 팝업 생성
				var $popupWrapperOrigin = $(''
				+ '<div class="pluginx-popup-wrapper">'
					+ '<div class="pluginx-popup">'
						+ '<div class="pluginx-popup-header">'
							+ '<div class="pluginx-popup-title">플러그인 설치가 필요합니다.</div>'
						+ '</div>'
						+ '<div class="pluginx-popup-content-wrapper">'
							+ '<div class="pluginx-popup-content">'
								+ '<div class="pluginx-popup-code"></div>'
								+ '<div class="pluginx-popup-summary"></div>'
							+ '</div>'
						+ '</div>'
						+ '<div class="pluginx-popup-footer">'
							+ '<div class="pluginx-trust-check-wrapper">'
								+ '<input type="checkbox" id="pluginx-trust-check" />'
								+ '<label for="pluginx-trust-check">이 플러그인들을 신뢰</label>'
							+ '</div>'
							+ '<div class="pluginx-btn-accept pluginx-close pluginx-btn">사용</div>'
							+ '<div class="pluginx-btn-deny pluginx-close pluginx-btn">거부</div>'
						+ '</div>'
					+ '</div>'
				+ '</div>')

				// 만든팝업 캐싱
				installPopup._$popupWrapper = $popupWrapperOrigin;
			}
			var $popupWrapper = installPopup._$popupWrapper.clone();
			
			var closePopup = function(callback){
				$popupWrapper.closest(".pluginx-popup-wrapper").fadeOut(0.3, function(){
					$popupWrapper.remove();
					callback($popupWrapper);
				});
			};

			// 팝업 외부 클릭시 팝업 종료
			$popupWrapper.click(function(e){
				if(e.target == $popupWrapper[0]){
					closePopup(rejectCallback);
				}
			})

			// 팝업 종료 이벤트
			$popupWrapper.find(".pluginx-btn-accept").click(function(){
				closePopup(resolveCallback);
			});
			$popupWrapper.find(".pluginx-btn-deny").click(function(){
				closePopup(rejectCallback);
			})

			return $popupWrapper

		},
		// 플러그인 인스톨 페이지에 설정값 바인딩 후 표시
		show:function(pluginItems){ return new Promise(function(resolve, reject){
			var $popupWrapper = installPopup._getPopupElement({
				resolveCallback: function($popupWrapper){ resolve({
					trust: $popupWrapper.find("#pluginx-trust-check").is(":checked"),
				}); },
				rejectCallback: function(){ reject(); },
			});

			var formatTimestamp = function(timestamp){
				timestamp = timestamp.toString();
				return timestamp.substring(0,4) + "-" + timestamp.substring(4,6) + "-" + timestamp.substring(6,8) + " " + timestamp.substring(8,10) + ":" + timestamp.substring(10,12) + ":" + timestamp.substring(12,14);
			};

			pluginItems.forEach(function(pluginItem){
				var $plugin = $popupWrapper.find(".pluginx-popup-content").eq(0).clone().css({display: "block"});

				$plugin.find(".pluginx-popup-code").text(pluginItem.script); // 자동 이스케이프
				$plugin.find(".pluginx-popup-summary").append("<li> 원본문서 : " + pluginItem.doc + "</li>");
				$plugin.find(".pluginx-popup-summary").append("<li> 최초작성자 : " + pluginItem.creator + "</li>");
				$plugin.find(".pluginx-popup-summary").append("<li> 수정자 : " + pluginItem.revUser + "</li>");
				$plugin.find(".pluginx-popup-summary").append("<li> 수정일 : " + formatTimestamp(pluginItem.revTimestamp) + "</li>");
				var patternList = [
					{ // 이전 신뢰된 편집자와 현재 편집자가 다른 경우
						ciritica: function(pluginItem){ return pluginItem.prevTrusted.revid && pluginItem.prevTrusted.revUser !== pluginItem.revUser; },
						severity: "danger",
						message: "이전 신뢰된 편집자와 현재 편집자가 다릅니다. 사용자를 확인해주세요.",
					},
					{ // 신뢰된 버전과 현재 버전의 리비전이 동일한 경우
						ciritica: function(pluginItem){ return pluginItem.prevTrusted.revid === pluginItem.revid; },
						severity: "safe",
						message: "이전에 신뢰된 플러그인입니다.",
					},
					{// 이전에 신뢰되었지만 현재 버전이 다른 경우
						ciritica: function(pluginItem){ 
							return pluginItem.prevTrusted.revid 
								&& pluginItem.prevTrusted.revid !== pluginItem.revid 
								&& pluginItem.prevTrusted.revUser === pluginItem.revUser;
						},
						severity: "safe",
						message: "이전에 신뢰되었지만 버전업으로 재확인이 필요합니다.",
					},
				];
				for(var patternKey in patternList){
					var pattern = patternList[patternKey];

					if(pattern.ciritica(pluginItem)){

						$plugin.find(".pluginx-popup-summary").append("<li class='severity " + pattern.severity + "'>" + pattern.message + "</li>");
					}
				}
				$popupWrapper.find(".pluginx-popup-content-wrapper").append($plugin);
			});

			$popupWrapper.appendTo("body").fadeIn(0.2);
		})},
	};

	// 문서에서 사용중인 플러그인 확인
    var pluginItems = getPluginList();

	// 모든 플러그인의 신뢰여부 체크
	pluginItems = pluginItems.map(function(pluginItem){
		return Object.assign(pluginItem, {prevTrusted: setting.getTrustedItemByDoc(pluginItem.doc) || {}});
	});

	// 플러그인의 신뢰여부 확인
	var isPluginTrusted = pluginItems.every(function(pluginItem){
		return pluginItem.prevTrusted.revTimestamp == pluginItem.revTimestamp;
	});

	// 플러그인의 신뢰여부 확인, 미신뢰시 팝업 표시
	var pluginTrustRequestPromise = isPluginTrusted ? Promise.resolve() : installPopup.show(pluginItems); //isPluginTrusted

	// todo localstoarge에서 대조 후 리비전이 다를때만 사용자 확인 필요
	pluginTrustRequestPromise.then(function(result){
		result = result || {};
		// 사용자가 플러그인을 신뢰할 경우 localStoarge에 저장
		if(result.trust){
			setting.setTrustedItems(pluginItems);
		}
		// 스크립트 실행 
		pluginItems.forEach(function(pluginItem){
    		eval(pluginItem.script);
		});
	});
}
$(pluginXCore);