
참고로 여기서 한글은 진짜 이 한글 프로그램이 맞다.
어제 연등 때 취사반 애들이랑 얘기하다 들었던 이야기인데, 매일 한글 파일로 이루어진 식단 내용을 수정해야 한다고 한다. 그러면서 그 과정을 자동화해 줄 수 있는지 물어봤었는데, 난 프로그래머니까 일단 된다고 했다.
진짜 되는지 알아보려고 오늘 확인해본 것들을 올린다.

우선 한글 파일에 무지개색 표 하나를 만들고 시작한다.
표를 복사한 다음, Clipboard Inspector에 들어가서 텍스트 데이터를 확인해 보았다.

표 안의 텍스트가 text/plain으로 있었고,

엄청 긴 text/html 데이터,

그리고 엄청 긴 text/rtf 데이터가 있었다.
그냥 한글에서 복사하고 붙여넣으면, 별다른 문제 없이 잘 붙여넣어진다. 즉 내가 데이터를 임의로 생성해도 이 셋만 있으면 한글에서 정상적으로 붙여넣어질 것이다.
그러면 html 파일을 어떻게 구성해야 할지 감이 왔다.
<!DOCTYPE html>
<textarea placeholder="text/plain"></textarea>
<textarea placeholder="text/html"></textarea>
<textarea placeholder="text/rtf"></textarea>
<button>복사!</button>
<script>
document.querySelector('button').addEventListener('click', e => {
const item = {};
for (const e of document.querySelectorAll('textarea')) {
item[e.placeholder] = new Blob([e.value], { type: e.placeholder });
}
navigator.clipboard.write([
new ClipboardItem(item)
]).then(v => {
console.log('복사 완료');
}).catch(e => {
console.error(`복사 실패: ${e}`);
});
});
</script>
버튼을 누르면 각 textarea에서 텍스트를 가져와서 item을 만들고, navigator의 clipboard api로 클립보드에 쓴다.
이거를 html로 실행해 보면,

창이 3개.

각 위치에 아까 Inspector에서 가져온 파일을 넣고 복사 버튼을 누르면...?

안됨

스택오버플로를 뒤져 보면 MIME 타입을 3개밖에 지원 안 한다고 한다.
그래도 text/plain이랑 text/html은 지원하니까 text/rtf만 없애고 한 번 다시 실행해 보면...

복사도 되고...

잘 붙여넣어진다.

다만 이미 있는 표에 덮어씌워서 붙여넣으려고 하면 표가 망가진다..
new Blob([e.value.replace('빨강', '빠아아아알강')], { type: e.placeholder });
마지막으로 텍스트 수정이 되는지만 확인해보고 마치도록 하자.

잘 된다.
이제 한글 파일을 html로 수정해달라는 요청을 받아도 js로 hwp 파일 파서를 직접 만들지 않는 한에서 어떻게든 할 수 있게 되었다.
마지막으로 테스트에 쓰인 최종 버전을 올린다. Clipboard Inspector 소스에서 extractData를 가져와서 앞에 조건문 하나를 덧붙였다.
<!DOCTYPE html>
<textarea placeholder="text/plain"></textarea>
<textarea placeholder="text/html"></textarea>
<button id="load">불러오기!</button>
<button id="copy">복사!</button>
<script>
// https://evercoder.github.io/clipboard-inspector/
async function extractData(data) {
if (!data) {
return undefined;
}
if (Array.isArray(data)) data = data[0];
const file_info = file =>
file
? {
name: file.name,
size: file.size,
type: file.type,
url: URL.createObjectURL(file)
}
: null;
if (data instanceof DataTransfer) {
return {
type: 'DataTransfer',
types: Array.from(data.types).map(type => ({
type,
data: data.getData(type)
})),
items: data.items
? Array.from(data.items).map(item => ({
kind: item.kind,
type: item.type,
as_file: file_info(item.getAsFile())
}))
: null,
files: data.files ? Array.from(data.files).map(file_info) : null
};
}
if (data instanceof ClipboardItem) {
return {
type: 'ClipboardItem',
types: await Promise.all(
Array.from(data.types).map(async type => {
const blob = await data.getType(type);
return {
type: type,
data: blob.type.match(/^text\//)
? await blob.text()
: file_info(blob)
};
})
)
};
}
return undefined;
}
document.querySelector('#load').addEventListener('click', async e => {
const extracted_data = await extractData(await navigator.clipboard.read());
console.log(extracted_data);
for (const d of extracted_data.types) {
document.querySelector(`textarea[placeholder="${d.type}"]`).value = d.data;
}
});
document.querySelector('#copy').addEventListener('click', e => {
const item = {};
const replacer = [
t => t.replace('빨강', '빠아아아알강'),
];
for (const e of document.querySelectorAll('textarea')) {
let text = e.value;
for (const r of replacer) {
text = r(text);
}
item[e.placeholder] = new Blob([text], { type: e.placeholder });
}
navigator.clipboard.write([
new ClipboardItem(item)
]).then(v => {
console.log('복사 완료');
}).catch(e => {
console.error(`복사 실패: ${e}`);
});
});
</script>
+)

뭐야 이게 왜 떠요 아깐 안떴잖아
난 역시 한글과컴퓨터가 싫다.