// <nowiki>
// @todo api.get을 호출하면 소요되는 시간 동안 문서 내용이 바뀔 수 있음.
(function(mw, $) {
"use strict";
/**
* "==[[페미니즘]]=="과 같은 문자열에서 "페미니즘"을 가져오기 위한 정규식.
* @constant
* @type {RegExp}
*/
var SECTION_TITLE_REGEXP = /^=+\s*\[\[([^=\]\[]+)\]\]\s*=+$/;
/**
* 한줄인용이 저장되는 문서 이름.
* @constant
* @type {string}
*/
var DATA_TITLE = "페미위키:한줄인용";
/**
* 링크로 포함할 문서 이름, 예를 들어 "페미니즘은 이런 저런 것이다."라는 트윗에 페미니즘 문서로 링크를 건다면 "페미니즘"
* @type {string}
*/
var linkArticle;
/**
* @type {object}
*/
var cache = {
revId: null,
wikitext: null,
sectionId: null,
sectionWikitext: null
};
/**
* @type {mw.Api}
*/
var api;
/**
* @type {TweetbotQuickEditor}
*/
var tweetbotQuickEditor;
function main() {
if (mw.config.get("wgAction") != "view") {
return;
}
mw.user.getRights().then(function(rights) {
if (rights.indexOf("edit") < 0) {
return;
}
linkArticle = mw.config.get("wgPageName").replace(/_/g, " ");
api = new mw.Api();
// 메뉴에 한줄인용 버튼 추가
$(
mw.util.addPortletLink(
"p-actions",
mw.util.getUrl(DATA_TITLE),
"한줄인용",
"p-tweetbot",
"이 문서에 대한 한줄인용을 편집합니다."
)
).on("click", onClickPortletLink);
});
}
/**
* @param {Event} event
*/
function onClickPortletLink(event) {
event.preventDefault();
if (!cache.revId) {
// [[페:한줄인용]]]을 가져옵니다.
api
.get({
action: "parse",
page: DATA_TITLE,
prop: "revid|wikitext"
})
.then(function(data) {
storeCache({
revId: data.parse.revid,
wikitext: data.parse.wikitext["*"],
sectionId: null,
sectionWikitext: null
});
findSectionIdAndOpenEditor();
});
return;
}
// 저장된 것보다 더 최신인 리비전이 있는지 확인합니다.
api
.get({
action: "parse",
page: DATA_TITLE,
prop: "revid"
})
.then(function(data) {
if (cache.revId == data.parse.revid && cache.sectionWikitext) {
openEditor(cache.sectionWikitext);
return;
}
api
.get({
action: "parse",
page: DATA_TITLE,
prop: "wikitext"
})
.then(function(data) {
storeCache({
wikitext: data.parse.wikitext["*"],
sectionId: null,
sectionWikitext: null
});
findSectionIdAndOpenEditor();
});
});
}
/**
*
* @param {object} newer
*/
function storeCache(newer) {
var givenKeys = ["revId", "wikitext", "sectionId", "sectionWikitext"];
for (var key in newer) {
if (givenKeys.indexOf(key) < 0) {
console.error("invaild key " + key + " is used");
return;
}
cache[key] = newer[key] === null ? null : newer[key];
}
}
/**
*
*/
function findSectionIdAndOpenEditor() {
// 현재 보고 있는 문서에 대해 이미 작성된 한줄인용이 있는지 검사합니다.
if (findSectionId()) {
api
.get({
action: "parse",
page: DATA_TITLE,
section: cache.sectionId,
prop: "wikitext"
})
.then(function(data) {
storeCache({
sectionWikitext: data.parse.wikitext["*"]
});
openEditor(cache.sectionWikitext);
});
} else {
OO.ui
.confirm(
linkArticle +
" 문서에 대한 한줄인용이 아직 없습니다. 추가하시겠습니까?"
)
.done(function(confirmed) {
if (confirmed) {
openEditor("== [[" + linkArticle + "]] ==\n* ");
}
});
}
}
/**
/* 현재 보고 있는 문서에 대해 이미 작성된 한줄인용이 있는지 검사합니다.
*/
function findSectionId() {
var found =
cache.wikitext.match(
new RegExp(
"^=+\\s*\\[\\[" +
linkArticle.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") +
"\\]\\]\\s*=+$",
"m"
)
) !== null;
if (found) {
var titles = cache.wikitext
.match(new RegExp(SECTION_TITLE_REGEXP, "gm"))
.map(function(line) {
return line.match(new RegExp(SECTION_TITLE_REGEXP, "m"))[1];
});
// sectionId는 0이 도입부이고 제목이 있는 문단은 1부터 시작합니다.
storeCache({
sectionId: titles.indexOf(linkArticle) + 1
});
}
return found;
}
/**
* @param text
*/
function openEditor(text) {
var wm = OO.ui.getWindowManager();
var editor = getTweetbotQuickEditor();
if (!wm.hasWindow(editor)) {
wm.addWindows([editor]);
}
wm.openWindow(editor, {
text: text
});
}
/**
* @return {TweetbotQuickEditor}
*/
function getTweetbotQuickEditor() {
if (tweetbotQuickEditor === undefined) {
tweetbotQuickEditor = new TweetbotQuickEditor();
}
return tweetbotQuickEditor;
}
/**
* 트윗을 편집하는 편집기.
*
* @class TweetbotQuickEditor
*/
function TweetbotQuickEditor(config) {
TweetbotQuickEditor.super.call(this, config);
}
OO.inheritClass(TweetbotQuickEditor, OO.ui.ProcessDialog);
TweetbotQuickEditor.static.name = "TweetbotQuickEditor";
TweetbotQuickEditor.static.actions = [
{
flags: ["primary", "progressive", "disabled"],
label: "완료",
action: "publish"
},
{ flags: "safe", label: "취소" }
];
TweetbotQuickEditor.prototype.initialize = function() {
TweetbotQuickEditor.super.prototype.initialize.call(this);
this.panel = new OO.ui.PanelLayout({
padded: true,
expanded: false
});
this.content = new OO.ui.FieldsetLayout();
this.editor = new OO.ui.MultilineTextInputWidget({
autosize: true
});
this.field = new OO.ui.FieldLayout(this.editor, {
label: "아래 내용을 수정하고 완료를 누르세요.",
align: "top"
});
this.content.addItems([this.field]);
this.panel.$element.append(this.content.$element);
this.$body.append(this.panel.$element);
this.editor.connect(this, {
change: "onInputChange"
});
};
TweetbotQuickEditor.prototype.getReadyProcess = function(data) {
return TweetbotQuickEditor.super.prototype.getReadyProcess
.call(this, data)
.next(function() {
this.editor.moveCursorToEnd();
}, this);
};
TweetbotQuickEditor.prototype.onInputChange = function(value) {
this.actions.setAbilities({
publish: value.length !== 0 && value !== cache.sectionWikitext
});
};
TweetbotQuickEditor.prototype.getBodyHeight = function() {
return this.panel.$element.outerHeight(true);
};
TweetbotQuickEditor.prototype.getSetupProcess = function(data) {
data = data || {};
return TweetbotQuickEditor.super.prototype.getSetupProcess
.call(this, data)
.next(function() {
this.editor.setValue(data.text);
}, this);
};
TweetbotQuickEditor.prototype.getActionProcess = function(action) {
var dialog = this;
var editorText = this.editor.getValue();
if (action != "publish")
return TweetbotQuickEditor.super.prototype.getActionProcess.call(
this,
action
);
return new OO.ui.Process(function() {
api
.get({
action: "parse",
page: DATA_TITLE,
prop: "revid"
})
.then(function(data) {
if (cache.revId == data.parse.revid) {
if (cache.sectionId) {
edit(cache.sectionId, editorText);
storeCache({
sectionWikitext: editorText
});
} else {
findAndAppend(editorText);
}
dialog.close({ action: action });
return;
}
// wikitext를 가져왔을 때의 revId와 지금의 revId가 다르다면 충돌이 일어나지 않았는지 확인
api
.get({
action: "parse",
page: DATA_TITLE,
prop: "wikitext"
})
.then(function(data) {
storeCache({
revId: data.parse.revid,
wikitext: data.parse.wikitext["*"]
});
// 문단이 있는지 검사
if (findSectionId()) {
// 문단이 원래부터 있었거나, 없다가 생겼다면 충돌 검사 후 저장
api
.get({
action: "parse",
page: DATA_TITLE,
section: cache.sectionId,
prop: "wikitext"
})
.then(function(data) {
var sectionWikitext = data.parse.wikitext["*"];
if (sectionWikitext == cache.sectionWikitext) {
// 기존 내용과 같다면 편집 충돌이 없으므로 저장
edit(sectionId, editorText);
storeCache({
wikitext: null,
sectionWikitext: editorText
});
dialog.close({ action: action });
return;
}
// 충돌이므로 덮어 쓸 것인지 질문
// @todo diff 보이기
OO.ui
.confirm(
"작성하는 동안 다른 편집이 있었습니다. 무시하고 덮어 쓰시겠습니까?"
)
.done(function(confirmed) {
if (confirmed) {
edit(cache.sectionId, editorText);
storeCache({
sectionWikitext: editorText
});
dialog.close({ action: action });
}
});
});
return;
}
// 문단이 원래부터 없었거나, 있다가 없어졌다면 새 문단으로 추가
api
.get({
action: "parse",
page: DATA_TITLE,
section: findSectionIdToInsert(),
prop: "wikitext"
})
.then(function(data) {
edit(id, data.parse.wikitext["*"] + "\n\n" + editorText);
storeCache({
wikitext: null,
sectionId: cache.sectionId + 1,
sectionWikitext: editorText
});
dialog.close({ action: action });
});
});
});
}, this);
};
function findAndAppend(wikitext) {
var idToInsert = findSectionIdToInsert();
api
.get({
action: "parse",
page: DATA_TITLE,
section: idToInsert,
prop: "wikitext"
})
.then(function(data) {
edit(idToInsert, data.parse.wikitext["*"] + "\n\n" + wikitext);
storeCache({
sectionId: idToInsert + 1,
sectionWikitext: wikitext
});
});
}
/**
* 이 문서에 대한 한줄인용이 아직 없을 때 사전 순서 그 이전 문단 번호를 반환.
*/
function findSectionIdToInsert() {
var titles = cache.wikitext
.match(new RegExp(SECTION_TITLE_REGEXP, "gm"))
.map(function(line) {
return line
.match(new RegExp(SECTION_TITLE_REGEXP, "m"))[1]
.replace(" ", "");
});
var _linkArticle = linkArticle.replace(" ", "");
var id;
for (id = 0; id < titles.length; id++) {
if (titles[id].localeCompare(_linkArticle, "ko") > 0) {
break;
}
}
return id;
}
/**
*
* @param {string} text
*/
function edit(sectionId, text) {
api
.edit(DATA_TITLE, function(revision) {
return {
section: sectionId,
summary: "/*" + linkArticle + "*/",
text: text,
tags: "fw-tweetbot-quick-editor"
};
})
.then(
function() {
mw.notify("저장되었습니다.");
storeCache({
revId: null,
wikitext: null
});
},
function(error) {
mw.notify(error.message);
}
);
}
main();
// </nowiki>
})(mediaWiki, jQuery);