1. 소개
이 섹션은 규범적이지 않습니다.
이 명세서는 시스템 클립보드가 웹 애플리케이션에 어떻게 노출되는지 정의합니다.
이 명세서에는 두 가지 일반적인 API가 설명되어 있습니다:
-
클립보드 이벤트 API - 이 API는 잘라내기, 복사, 붙여넣기와 같은 일반적인 클립보드 작업에 연결하여 웹 애플리케이션이 필요에 따라 클립보드 데이터를 조정할 수 있는 방법을 제공합니다.
-
비동기 클립보드 API - 이 API는 클립보드 데이터를 직접 읽고 쓸 수 있는 접근을 제공합니다. 이는 강력한 기능으로 간주되기 때문에, 이 API에 대한 접근은 권한에 의해 제어됩니다.
2. 사용 사례
이 섹션은 규범적이지 않습니다.
2.1. 기본 클립보드 동작 변경
기본 클립보드 작업(잘라내기/복사/붙여넣기)을 변경하고 싶은 다양한 시나리오가 있습니다. 몇 가지 예시를 들면 다음과 같습니다:
- 메타데이터 문서 저장소에서 텍스트를 복사할 때, 복사된 텍스트에 원본 콘텐츠에 대한 메타데이터를 포함시키는 것이 유용할 수 있습니다.
- 서식 있는 콘텐츠 편집 하이퍼링크나 기타 구조를 포함한 텍스트를 복사할 때, 중요한 정보를 보존하기 위해 콘텐츠를 다시 포맷하는 기능이 종종 필요합니다.
- 내장 의미를 가진 그래픽 웹 애플리케이션에서 서식 있는 텍스트 또는 [SVG11]과 같은 그래픽 콘텐츠를 조작할 수 있도록, 렌더링된 콘텐츠만 복사하는 것이 아니라 더 많은 정보를 복사할 수 있는 메커니즘을 제공하는 것이 유용합니다.
- 수학적 정보 수학과 같은 콘텐츠의 경우, 단순히 렌더링된 텍스트를 복사하여 다른 애플리케이션에 붙여넣으면 대부분의 의미가 손실됩니다. 예를 들어 MathML을 평문 텍스트로 복사할 때는 "^" 기호로 거듭제곱을 표시하는 등 변환이 필요합니다. XML 소스를 클립보드에 넣고, 붙여넣기 시점에 적절한 변환이 이루어질 수도 있습니다.
2.2. 원격 클립보드 동기화
원격 기기와 통신하는 웹 애플리케이션(예: 원격 액세스 또는 원격 셸 애플리케이션)에서는 클립보드 데이터가 두 기기 간에 동기화되어야 할 필요가 자주 있습니다.
이 사용 사례에서 중요한 점은 사용자 제스처나 상호작용 없이도 클립보드에 접근해야 한다는 것입니다.
write()
메서드를 통해 로컬 클립보드에 데이터를 씁니다. clipboardchange
이벤트를 감지하고, 클립보드가 업데이트될 때마다 read()
메서드로 클립보드에서 새로운 데이터를 읽은 후, 그 데이터를 원격 기기로 전송합니다. 2.3. 클립보드 작업 트리거
사용자 에이전트에 대체 인터페이스를 제공하는 애플리케이션은 때때로 사용자 에이전트에서 클립보드 작업을 트리거할 필요가 있습니다.
예를 들어, 보다 접근성 높은 인터페이스를 제공하는 화면 판독기 애플리케이션을 생각해 볼 수 있습니다. 이 판독기는 콘텐츠를 표시하고 사용자가 상호작용할 수 있도록 하지만, 클립보드 복사와 같은 작업은 브라우저에서 수행되어야 클립보드 콘텐츠가 올바르게(브라우저가 복사 시 추가하는 메타데이터 포함) 설정됩니다.
3. 용어 정리
editable context는 editing host이거나 textarea 요소, 또는 type 속성이 "text", "search", "tel", "url", "email", "password", "number" 중 하나로 설정된 input 요소를 의미합니다.
4. 모델
플랫폼은 시스템 클립보드를 제공합니다.
시스템 클립보드는 여러 시스템 클립보드 아이템의 목록을 가지고 있으며, 이들은 총칭해서 시스템 클립보드 데이터라 부릅니다.
각 시스템 클립보드 아이템은 여러 시스템 클립보드 표현의 목록을 가집니다.
각 시스템 클립보드 표현은 문자열인 name과 바이트 시퀀스인 data를 가집니다.
시스템 클립보드에는 클립보드 변경 횟수가 있으며, 이는 시스템 클립보드 데이터가 수정될 때마다 변경되는 값이다.
5. 클립보드 이벤트
5.1. 클립보드 이벤트 인터페이스
ClipboardEvent 인터페이스는 Event
인터페이스를 확장합니다.
dictionary :ClipboardEventInit EventInit {DataTransfer ?=clipboardData null ; };
- clipboardData
-
이 이벤트와 관련된 데이터 및 메타데이터를 저장하는
DataTransfer객체입니다.
[Exposed =Window ]interface :ClipboardEvent Event {(constructor DOMString ,type optional ClipboardEventInit = {});eventInitDict readonly attribute DataTransfer ?; };clipboardData
- clipboardData
-
clipboardData 속성은
DataTransfer인터페이스의 인스턴스로, 스크립트가 사용자가 복사, 잘라내기, 붙여넣기 작업을 할 때 시스템 클립보드의 값을 읽고 조작할 수 있도록 합니다. 관련 drag data store는 시스템 클립보드의 필터링된 실시간 뷰로, 구현체가 스크립트가 안전하게 접근할 수 있다고 아는 필수 데이터 타입만 노출합니다. 합성 이벤트에서는 drag data store에 이벤트를 생성한 스크립트가 추가한 데이터만 포함됩니다.clipboardData 객체의
items및files속성을 통해 클립보드에서 다중 파트 혹은 비텍스트 데이터를 처리할 수 있습니다.
이 인터페이스는 이벤트를 생성하는 데 사용할 수 있습니다. 아래는 예시입니다:
var pasteEvent = new ClipboardEvent('paste');
pasteEvent.clipboardData.items.add('My string', 'text/plain');
document.dispatchEvent(pasteEvent);
참고: 합성 클립보드 이벤트는 실제로 클립보드나 문서를 변경하지 않습니다. 즉, 위의 스크립트는 paste 이벤트를 발생시키지만, 데이터가 문서에 붙여넣어지지는 않습니다.
5.2. 클립보드 이벤트
5.2.1.
clipboardchange 이벤트
clipboardchange
이벤트는 시스템 클립보드의 내용이 변경될
때마다 발생합니다. 이러한 변경은 다음과 같은 원인(포괄적이지 않음)일 수 있습니다:
-
사용자가 직접 잘라내기나 복사 작업을 수행
-
스크립트가 § 7 비동기 클립보드 API를 사용하여 클립보드에 쓰기
-
사용자 에이전트 외부에서 클립보드가 갱신되는 작업
5.2.1.1. clipboardchange 이벤트 발생 단계
Document
document에 대해 clipboardchange 이벤트를 발생시키려면:
-
document가 고정 활성화를 갖지 않고 document가 클립보드에서 읽을 권한도 갖지 않으면, 반환한다.
-
global을 document의 관련 전역 객체로 둔다.
-
document가 시스템 포커스를 가지면:
-
changeId를 document가 주어졌을 때 changeId 생성을 실행한 결과로 둔다.
-
eventInit을 새
ClipboardChangeEventInit딕셔너리로 두며, 그types멤버는 types로, 그changeId멤버는 changeId로 설정한다. -
eventInit을 사용하여,
ClipboardChangeEvent를 사용해 global에서clipboardchange라는 이름의 이벤트를 발화한다.
-
document가 시스템 포커스를 갖지 않으면:
-
document의 clipboardchange 보류 플래그를 true로 설정한다.
-
사용자 에이전트는 이벤트가 전달되기 전에 새 변경 사항에 의해 대체된 클립보드 변경에 대해
clipboardchange
이벤트 발생을 건너뛸 수 있습니다(MAY).
이 최적화는 클립보드가 빠르게 연속 변경되는 상황에서 성능을 높일 수 있습니다. 왜냐하면 오래된 변경 알림을 전달하는 것은 웹 애플리케이션에 가치 없이 처리 리소스만 소모하기 때문입니다.
5.2.1.2. 문서 포커스 단계
Document
document가 시스템 포커스를 얻을 때:
-
document의 clipboardchange 보류 플래그가 true이면:
-
document의 clipboardchange 보류 플래그를 false로 설정한다.
-
changeId를 document가 주어졌을 때 changeId 생성을 실행한 결과로 둔다.
-
eventInit을 새
ClipboardChangeEventInit딕셔너리로 두며, 그types멤버는 types로, 그changeId멤버는 changeId로 설정한다. -
global을 document의 관련 전역 객체로 둔다.
-
eventInit을 사용하여,
ClipboardChangeEvent를 사용해 global에서clipboardchange라는 이름의 이벤트를 발화한다.
-
중첩된 브라우징 컨텍스트의 문서의 경우, clipboardchange
이벤트는 각 Document
에서 자신의 포커스 상태에 따라 독립적으로 발생합니다. 클립보드 변경은 시스템 포커스가 있는 단일 문서(그 문서에 지속적 활성화 또는 영구적인 클립보드 권한이 있는 경우)에 대해 이벤트를 발생시킵니다.
참고: clipboardchange 이벤트는 지속적
활성화 이후에만 사용할 수 있으며, 문서에 클립보드에서 읽기 위한 영구 권한이 없는 한 그렇습니다. 영구 클립보드 권한을 지원하는 사용자 에이전트에서는, 해당 권한이 있는 사이트가
sticky activation 없이도 clipboardchange 이벤트를 받을 수 있습니다. 왜냐하면 그 권한이 이미 더 민감한 클립보드 데이터에 접근 권한을 부여하기
때문입니다.
changeId
는 각 클립보드 변경 작업에 대한 고유 식별자를 제공합니다. 동일한 클립보드 변경에 대해 동일한 storage key를 가진 모든 창과
탭은 동일한 changeId
값을 가진 이벤트를 받으므로, 여러 창이 있을 때도 한 번만 이벤트를 처리하도록 중복 처리가 가능합니다.
이 식별자는 storage key에 한정되며 교차 storage key 상관 기능은
제공하지 않습니다.
clipboardchange
이벤트는 버블링되지 않으며 취소도 불가능합니다.
이 이벤트는 사용자 동작이 아니라 시스템
클립보드의 상태 변화에 의해 트리거되기 때문입니다.
dictionary :ClipboardChangeEventInit EventInit {sequence <DOMString >= [];types bigint = 0; };changeId
[Exposed =Window ]interface :ClipboardChangeEvent Event {(constructor DOMString ,type optional ClipboardChangeEventInit = {});eventInitDict readonly attribute FrozenArray <DOMString >;types readonly attribute bigint ; };changeId
- types
-
이벤트가 발화되었을 때 시스템 클립보드에서 사용할 수 있는 필수 데이터 타입을 나타내는
DOMString객체들의FrozenArray를 반환한다. 핑거프린팅 표면을 제한하기 위해 선택적 데이터 타입과 사용자 정의 형식은 제외된다. - changeId
-
이 특정 클립보드 변경 작업의 고유 식별자를 나타내는
bigint를 반환한다. 이 식별자는 동일한 클립보드 변경에 대해 같은 저장소 키를 가진 모든 창과 탭에서 일관되며, 여러 창이 같은 클립보드 변경 알림을 받을 때 애플리케이션이 이벤트 중복을 제거할 수 있게 한다.changeId는 암호학적으로 도출된 128비트 정수이다. 유일한 보장은 무언가가 클립보드에 쓰인 후에는changeId가 쓰기 작업 전과는 다른 값을 산출한다는 것이다.
5.2.1.4. ChangeId 생성
Document
document에 대해 changeId를
생성하려면:
-
globalChangeId를 시스템 클립보드의 현재 상태를 나타내는 사용자 에이전트별 고유 식별자로 둔다. 이 식별자는 시스템 클립보드가 수정될 때마다 변경되며, 사용자 에이전트가 다시 시작될 때 재설정된다.
-
storageKey를 document의 관련 설정 객체가 주어졌을 때 비저장소 목적을 위한 저장소 키 얻기를 실행한 결과로 둔다.
-
storageKeyBytes를 storageKey의 사용자 에이전트별 이진 표현으로 둔다.
-
hashedValue를 globalChangeId(바이트로서)와 storageKeyBytes의 연결에 암호학적 해시 함수(예: SHA-256)를 적용한 결과로 둔다.
-
hashedValue에서 도출된 128비트 정수(예를 들어 해시 출력의 처음 128비트를 취함)를 반환한다.
위 알고리즘은 같은 출처와 같은 파티셔닝을 가진 문서가 같은 클립보드 수정에 대해 동일한 change ID를 받도록 보장하여, 여러 창과 탭에 걸친 적절한 이벤트 중복 제거를 가능하게 하는 동시에, 추적에 사용될 수 있는 교차 파티션 상관관계를 방지한다. 클라이언트 측 저장소 파티셔닝 변경 사항이 저장소 키 정의에 통합됨에 따라, 이 접근 방식은 파티션 간 익명화를 자동으로 제공하게 된다.
changeId는
브라우저 재시작 후에도 지속되지 않는다. 사용자 에이전트가 다시 시작될 때 globalChangeId
카운터가 재설정되기 때문이다. 마찬가지로, 사용자가 사이트 데이터를 지우면 영향을 받는 탭은 새로고침되어야 하며, 이로 인해
이벤트 리스너가 다시 연결되고 새 change ID를 가진 향후 이벤트만 수신하게 된다.
합성 cut
및 copy
이벤트는 시스템 클립보드를 갱신하지
않으므로,
"clipboardchange" 이벤트를 트리거하지 않는다.
clipboardchange
이벤트는 웹 애플리케이션이 클립보드 변경을 효율적으로 모니터링하고
사용 가능한 데이터 형식에 기반해 동적인 사용자 인터페이스를 제공할 수 있게 한다:
// 여러 창이 있는 애플리케이션의 경우, 중복을 피하기 위해 처리된 change ID를 추적한다
const processedChangeIds = new Set();
// 클립보드 변경을 수신한다
navigator.clipboard.addEventListener('clipboardchange', (e) => {
// changeId를 사용해 여러 창에 걸친 이벤트를 중복 제거한다
if (processedChangeIds.has(e.changeId)) {
return; // 이 변경은 이미 처리되었다
}
processedChangeIds.add(e.changeId);
// 클립보드에서 어떤 데이터 타입을 사용할 수 있는지 확인한다
const hasText = e.types.includes('text/plain');
const hasHTML = e.types.includes('text/html');
const hasImage = e.types.includes('image/png');
// 사용 가능한 형식에 따라 UI를 갱신한다
document.getElementById('paste-text-btn').disabled = !hasText;
document.getElementById('paste-html-btn').disabled = !hasHTML;
document.getElementById('paste-image-btn').disabled = !hasImage;
// 원격 데스크톱 앱의 경우, 변경당 한 번만 클립보드를 원격과 동기화한다
if (hasText || hasHTML || hasImage) {
syncClipboardToRemote(e.changeId);
}
});
// 또는 onclipboardchange 속성을 사용할 수도 있다
// navigator.clipboard.onclipboardchange = (e) => { ... };
이 이벤트 기반 접근 방식은
read()
또는 readText()
같은 메서드로 클립보드를 폴링하는 것보다 더 효율적이며, 클립보드 접근에 사용자 활성화를 요구하는 브라우저에서도 작동한다.
UI가 타이머가 실행되기를 기다리지 않고 클립보드 변경에 즉시 반응할 수 있기 때문이다.
changeId는
여러 창이 있는 애플리케이션에 특히 유용하며,
같은 저장소 키를 가진 모든 창에 걸쳐 각 클립보드 변경이 한 번만 처리되도록
보장한다.
5.2.2. copy
이벤트
사용자가 복사 동작을 시작하면, 사용자 에이전트는
클립보드
이벤트를 발화한다. 그 이름은
copy이다.
이벤트가 취소되지 않으면, 현재 선택된 데이터가 시스템 클립보드에 복사된다. 현재 문서 선택은 영향을 받지 않는다.
copy
이벤트는 버블링되고, 취소 가능하며, 합성된다.
이 이벤트의 처리 모델에 대한 자세한 설명은 § 8.1 복사 동작을 참조하라.
합성 copy
이벤트는 수동으로 생성하고 디스패치할 수 있지만,
시스템 클립보드의 내용에는 영향을 주지
않는다.
5.2.3. cut
이벤트
사용자가 잘라내기 동작을 시작하면, 사용자 에이전트는
클립보드
이벤트를 발화한다. 그 이름은
cut이다.
편집 가능 컨텍스트에서는, 이벤트가
취소되지 않으면 이 동작은 현재 선택된 데이터를
시스템 클립보드에 놓고
문서에서 선택 영역을 제거한다.
cut
이벤트는 선택된 데이터가 제거되기 전에 발화된다. 잘라내기
작업이 완료되면, 선택 영역은 접힌다.
비-편집 가능
컨텍스트에서는, clipboardData가
빈 목록이 된다. 이 경우에도 cut
이벤트는 여전히 발화된다는 점에 유의하라.
cut
이벤트는 버블링되고, 취소 가능하며, 합성된다.
이 이벤트의 처리 모델에 대한 자세한 설명은 § 8.2 잘라내기 동작을 참조하라.
합성 cut
이벤트는 수동으로 생성하고 디스패치할 수 있지만,
문서 또는 시스템 클립보드의 내용에는
영향을 주지 않는다.
5.2.4.
paste
이벤트
사용자가 붙여넣기 작업을 시작하면, 사용자 에이전트는 클립보드 이벤트 paste를
발생시킵니다.
이 이벤트는 클립보드 데이터가 문서에 삽입되기 전에 발생합니다.
커서가 editable context에 있으면, 붙여넣기 동작은 해당 컨텍스트에서 지원하는 가장 적합한 포맷(있는 경우)으로 클립보드 데이터를 삽입합니다.
비-editable context에서는
붙여넣기 동작이 아무런 영향을 미치지 않지만,
paste
이벤트는 항상 발생합니다.
paste
이벤트는 버블링되며, 취소 가능하고, composed입니다.
이 이벤트의 처리 모델에 대한 자세한 설명은 § 8.3 붙여넣기 동작을 참고하세요.
합성 paste
이벤트를 수동으로 생성하여 디스패치할 수 있지만,
문서의 내용에는 영향을 주지 않습니다.
5.3. 다른 스크립트 및 이벤트와의 통합
5.3.1. 클립보드 수정을 허용하는 이벤트 핸들러
다음 조건 중 하나라도 true이면, 이벤트 핸들러는 클립보드에 쓸 수 있습니다:
-
이벤트를 트리거하는 동작이 사용자 에이전트의 자체 UI(예: "복사" 메뉴 항목이나 바로가기 키)에서 시작된 경우
-
이벤트를 트리거하는 동작이 팝업 표시가 허용된 스크립팅 스레드에서 시작된 경우
구현체는 해당 이벤트 타입이 사용자 의도를 반영한다고 판단될 경우, 다른 신뢰할 수 있는 이벤트 타입에도 클립보드 수정 권한을 허용할 수 있습니다. 또한 구현체가 특정 사이트나 앱에 원천 스레드와 무관하게 클립보드 수정을 신뢰하도록 구성할 수도 있습니다.
합성 cut
및 copy
이벤트는 시스템 클립보드의 데이터를 수정해서는 안 됩니다.
5.3.2. 클립보드 읽기를 허용하는 이벤트 핸들러
다음 조건 중 하나라도 true이면, 이벤트 핸들러는 시스템 클립보드에서 데이터를 읽을 수 있습니다:
-
이벤트를 트리거하는 동작이 사용자 에이전트의 자체 UI(예: "붙여넣기" 메뉴 항목이나 바로가기 키)에서 시작된 경우
-
동작을 트리거하는 스크립트가 구현체에 따라 클립보드 데이터를 읽을 권한을 부여받은 사이트에서 실행 중인 경우
-
동작을 트리거하는 이벤트가 클립보드 읽기 권한이 있는 앱에서 발생한 경우
합성 paste
이벤트는 스크립트에 실제 시스템 클립보드의 데이터 접근 권한을 주어서는 안 됩니다.
5.3.3. 서식 있는 텍스트 편집 API와의 통합
구현체가 스크립트를 통해 클립보드 명령을 실행하는 방법을 지원하는 경우, 예를 들어 document.execCommand() 메서드에 "cut", "copy",
"paste" 명령을 넘기는 방식이라면, 구현체는 반드시 해당 동작을 트리거하고, 그에 따라 관련 클립보드 이벤트를 디스패치해야 합니다.
스크립팅 API를 통해 복사, 잘라내기, 붙여넣기 동작을 트리거할 때 따라야 할 단계는 다음과 같습니다:
-
해당 동작을 동기적으로 실행합니다.
-
동작의 반환값을 API 호출의 반환값으로 사용합니다.
참고: 스크립팅 API를 통해 트리거된 복사 및 잘라내기 명령은 이벤트가 신뢰되고 사용자가 트리거한 경우 또는 구현체가 이를 허용하도록 설정된 경우에만 실제 클립보드 내용을 변경합니다. 붙여넣기 명령은 구현체가 허용하도록 설정된 경우에만 paste 이벤트를 발생시키고 클립보드 내용에 접근할 수 있습니다. 구현체가 클립보드 읽기 및 쓰기 접근을 허용하도록 구성하는 방법은 이 명세서의 범위에 포함되지 않습니다.
5.3.4. 다른 이벤트와의 상호작용
클립보드 작업이 키보드 입력에 의해 트리거된 경우, 구현체는 반드시 해당 클립보드 작업을 시작하는 이벤트를 발생시켜야 합니다. 이 이벤트는 비동기적이지만, 반드시 관련 키의 keyup 이벤트 전에 디스패치되어야 합니다.
잘라내기 및 붙여넣기 작업은 구현체가 지원하는 다른 이벤트(예: textInput, input, change, validation 이벤트, DOMCharacterDataModified, DOMNodeRemoved / DOMNodeInserted 등)를 발생시킬 수 있습니다. 이러한 이벤트는 cut/paste 이벤트 처리 후에 큐에 따라 발생합니다.
구현체는 복사 작업에 대해 textInput, input, change, validation과 같은 다른 입력 관련 이벤트를 발생시켜서는 안 됩니다.
5.3.5. 선택 영역이나 포커스를 수정하는 이벤트 리스너
이벤트 리스너가 선택 영역이나 포커스 가능한 영역을 수정한 경우, 클립보드 동작은 반드시 수정된 선택 영역에서 완료되어야 합니다.
6. 클립보드 이벤트 API
클립보드 이벤트 API를 사용하면 사용자 에이전트의 기본 잘라내기, 복사, 붙여넣기 동작을 오버라이드할 수 있습니다.
클립보드 접근은 표준 DataTransfer
메서드를 사용하여 items
를 변형합니다. 이 작업은 ClipboardEvent의
clipboardData
속성을 통해 이루어집니다.
이 API들은 ClipboardEvent
핸들러의 컨텍스트 내에서만 클립보드 데이터에 접근할 수 있습니다.
참고: 클립보드 이벤트 핸들러 외부에서 클립보드에 접근해야 한다면 § 7 비동기 클립보드 API를 참고하세요.
참고: 클립보드 이벤트 API는 동기적이므로, 할 수 있는 작업에 제한이 있습니다. 권한 요청이나 이미지 트랜스코딩 같은 잠재적으로 블로킹되는 동작은 지원하지 않습니다. 블로킹 또는 시간이 오래 걸리는 작업을 지원하는 더 강력한 API는 § 7 비동기 클립보드 API를 참고하세요.
6.1. 복사 이벤트 오버라이드
기본 copy
이벤트 동작을 오버라이드하려면 copy
이벤트 핸들러를 추가하고, 이 핸들러에서 preventDefault()
를 호출하여 이벤트를 취소해야 합니다.
이벤트를 취소해야만 시스템 클립보드가
clipboardData
의 데이터로 업데이트됩니다. ClipboardEvent
가 취소되지 않으면, 현재 문서 선택 영역의 데이터가 복사됩니다.
// 클립보드에 복사되는 내용을 덮어쓰는 예시
document.addEventListener('copy', function(e) {
// e.clipboardData는 처음에 비어 있지만, 복사하려는 데이터를 직접 설정할 수 있습니다.
e.clipboardData.setData('text/plain', 'Hello, world!');
e.clipboardData.setData('text/html', '<b>Hello, world!</b>');
// 현재 문서 선택 영역이 클립보드에 기록되는 것을 막기 위해 반드시 필요합니다.
e.preventDefault();
});
6.2. 잘라내기 이벤트 오버라이드
기본 cut
이벤트 동작을 오버라이드하려면 cut
이벤트 핸들러를 추가하고, 이 핸들러에서 preventDefault()
를 호출하여 이벤트를 취소해야 합니다.
이벤트를 취소해야만 시스템 클립보드가
clipboardData
의 데이터로 업데이트됩니다. ClipboardEvent
가 취소되지 않으면, 현재 문서 선택 영역의 데이터가 복사됩니다.
또한 cut
이벤트를 취소하면 문서가 갱신되지 않습니다(즉, 선택 영역이 제거되지 않습니다). 이벤트 핸들러에서 직접 선택된 텍스트를 문서에서 제거하는 작업을 해야 합니다.
// 클립보드에 복사되는 내용을 덮어쓰는 예시
document.addEventListener('cut', function(e) {
// e.clipboardData는 처음에 비어 있지만, 잘라내기 작업의 일부로 클립보드에 복사할 데이터를 직접 설정할 수 있습니다.
// 클립보드에 복사할 데이터를 직접 작성합니다.
e.clipboardData.setData('text/plain', 'Hello, world!');
e.clipboardData.setData('text/html', '<b>Hello, world!</b>');
// 잘라내기 작업을 취소할 것이므로, 선택된 텍스트를 직접 문서에서 제거해야 합니다.
deleteCurrentDocumentSelection();
// 현재 문서 선택 영역이 클립보드에 기록되는 것을 막기 위해 반드시 필요합니다.
e.preventDefault();
});
6.3. 붙여넣기 이벤트 오버라이드
기본 paste
이벤트 동작을 오버라이드하려면 paste
이벤트 핸들러를 추가하고, 이 핸들러에서 preventDefault()
를 호출하여 이벤트를 취소해야 합니다.
이벤트를 취소해야만 사용자 에이전트가 시스템 클립보드의 데이터로 문서를 갱신하지 않습니다.
또한 paste
이벤트를 취소하면 문서가 갱신되지 않습니다(즉, 아무것도 문서에 붙여넣어지지 않습니다). 이벤트 핸들러에서 직접 데이터를 문서에 붙여넣는 작업을 해야 합니다.
붙여넣기 시 drag data store mode 플래그가 읽기 전용이므로, setData()
를 paste
이벤트 핸들러에서 호출해도 삽입되는 데이터나 클립보드 데이터에는 영향을 주지 않습니다.
// 클립보드에 붙여넣는 내용을 덮어쓰는 예시
document.addEventListener('paste', function(e) {
// e.clipboardData에는 곧 붙여넣을 데이터가 들어 있습니다.
if (e.clipboardData.types.indexOf('text/html') > -1) {
var oldData = e.clipboardData.getData('text/html');
var newData = '<b>Ha Ha!</b> ' + oldData;
// 붙여넣기 작업을 취소할 것이므로, 직접 데이터를 문서에 붙여넣어야 합니다.
pasteClipboardData(newData);
// 기본 붙여넣기 동작을 막기 위해 반드시 필요합니다.
e.preventDefault();
}
});
6.4. 필수 데이터 타입
구현체는 아래 데이터 타입에 대해 운영체제의 기본 클립보드 포맷 설명을 인식해야 하며, DataTransferItemList
및 ClipboardItem
에서 붙여넣기 이벤트에 올바른 설명을 제공하고, 복사/잘라내기 이벤트에 대해 OS 클립보드에 올바른 데이터 포맷을 설정해야 합니다.
6.4.1. 클립보드에서 읽기
아래 데이터 타입은 클립보드에 해당하는 네이티브 타입이 있으면 붙여넣기 이벤트에서 노출되어야 합니다:
-
text/plain
-
text/html
-
image/png
6.4.2. 클립보드에 쓰기
아래 데이터 타입은 복사 및 잘라내기 이벤트에서 DataTransfer
객체에 추가될 때, 해당 네이티브 타입 설명과 함께 클립보드에 저장되어야 합니다.
-
text/plain
-
text/html
-
image/png
경고! 신뢰되지 않은 스크립트가 클립보드에 쓸 수 있는 데이터 타입은 보안 예방 차원에서 제한되어 있습니다. 신뢰되지 않은 스크립트가 클립보드에 로컬 소프트웨어의 보안 취약점을 유발하는 데이터를 넣으려 시도할 수 있습니다.
6.5. 선택적 데이터 타입
구현체는 아래 데이터 타입에 대해 운영체제의 기본 클립보드 포맷 설명을 인식할 수 있으며, ClipboardItem
에서 붙여넣기 이벤트에 올바른 설명을 제공하고, 복사/잘라내기 이벤트에 대해 OS 클립보드에 올바른 데이터 포맷을 설정할 수 있습니다.
아래 데이터 타입은 클립보드에 해당하는 네이티브 타입이 있으면 UA에서 노출할 수 있습니다:
-
text/uri-list
-
image/svg+xml
-
커스텀 포맷 "web "("web" 뒤에 U+0020 SPACE)로 시작하는 prefix와 suffix(끝부분에서 "web " 제거 후)가 MIME 타입 파싱 체크를 통과하는 경우
6.6. 비정제 데이터 타입
이 섹션은 규범적이지 않습니다.아래 데이터 타입은 UA가 반드시 정제(sanitize)하지 않아야 합니다:
-
image/png
아래 데이터 타입은 UA가 정제하지 않을 수도 있습니다:
선택적 비정제 데이터 타입은 웹 저자가 지정한 mime type 중 UA가 반드시 정제하지 않을 수도 있는 타입입니다. 선택적 비정제 데이터 타입의 유효 목록은 아래와 같습니다:
-
text/html
선택적 비정제 데이터 타입은 프라이버시 요구로 인해 UA에서 지원하지 않을 수 있습니다.
7. 비동기 클립보드 API
7.1. Navigator 인터페이스
partial interface Navigator { [SecureContext ,SameObject ]readonly attribute Clipboard ; };clipboard
7.2. ClipboardItem 인터페이스
typedef Promise <(DOMString or Blob )>; [ClipboardItemData SecureContext ,Exposed =Window ]interface {ClipboardItem constructor (record <DOMString ,ClipboardItemData >,items optional ClipboardItemOptions = {});options readonly attribute PresentationStyle presentationStyle ;readonly attribute FrozenArray <DOMString >types ;Promise <Blob >getType (DOMString );type static boolean supports (DOMString ); };type enum {PresentationStyle ,"unspecified" ,"inline" };"attachment" dictionary {ClipboardItemOptions PresentationStyle = "unspecified"; };presentationStyle
clipboardItem = new ClipboardItem([items, options])-
새로운
ClipboardItem객체를 생성합니다. items는 표현 목록을 나타내며, 각 표현은 mime type과Promise(해당 mime type에 맞는Blob또는DOMString)를 가집니다. options는ClipboardItemOptions를 채우는 데 사용할 수 있습니다. 아래 예시 참고.const format1= 'text/plain' ; const promise_text_blob= Promise. resolve( new Blob([ 'hello' ], { type: format1})); const clipboardItemInput= new ClipboardItem( {[ format1] : promise_text_blob}, { presentationStyle: "unspecified" }); clipboardItem.getType(type)- mime type type에 해당하는
Promise(그Blob)를 반환합니다. clipboardItem.types- clipboard item 객체에 포함된 mime type 목록을 반환합니다.
ClipboardItem.supports(type)- type이 필수 데이터 타입 또는 선택적 데이터 타입에 있으면 true, 아니면 false를 반환합니다.
클립보드 항목은 개념적으로 사용자가 "cut" 또는 "copy" 명령을 호출하여 공유 가능하게 만들고자 하는 의사를 나타낸 데이터이다. 클립보드 항목은 두 가지 목적을 수행한다. 첫째, 웹사이트가 사용자가 시스템 클립보드에 복사한 데이터를 읽을 수 있게 한다. 둘째, 웹사이트가 시스템 클립보드에 데이터를 쓸 수 있게 한다.
예를 들어, 사용자가 네이티브 애플리케이션의 스프레드시트에서 셀 범위를 복사하면, 하나의 클립보드 항목이 생성된다. 사용자가 데스크톱에서 파일 집합을 복사하면, 그 파일 목록은 여러 클립보드 항목으로 표현된다.
일부 플랫폼은 클립보드에 한 번에 둘 이상의 클립보드 항목을 둘 수 있도록 지원할 수 있지만, 다른 플랫폼은 이전 클립보드 항목을 새 항목으로 대체한다.
클립보드 항목은 표현의
목록을 가지며, 각 표현에는 연결된 MIME
타입(MIME 타입), 초깃값이 false인 isCustom 플래그가 있다.
이 플래그는 이 표현이 웹 사용자 정의 형식으로 취급되어야
하는지
(시스템 클립보드의 잘 알려진 형식과
반대로)를 나타내며, 데이터(ClipboardItemData)를
가진다.
웹 사용자 정의 형식은 isCustom이 true로 설정되어 있다.
사용자가 스프레드시트에서 셀 범위를 복사하는 예에서는, 이미지 (image/png), HTML 표(text/html), 일반 텍스트(text/plain), 또는 웹 사용자 정의 형식(web text/csv)으로 표현될 수 있다.
이러한 각 MIME 타입은 같은 클립보드 항목의 서로 다른 충실도 수준의 표현을 설명하며, 붙여넣기 중 대상 애플리케이션이 클립보드 항목을 더 쉽게 소비할 수 있게 한다.
셀 범위를 이미지로 사용할 수 있게 하면 사용자는 셀을 사진 편집 앱에 붙여넣을 수 있으며, text/plain 형식은 텍스트 편집기 앱에서 사용할 수 있다.
클립보드 항목은 표현 스타일
(PresentationStyle)을
가진다.
이는 클립보드 항목을 "붙여넣는" 앱이 적절한
표현의 내용을
붙여넣기 지점에 인라인으로 삽입해야 하는지, 또는 첨부 파일로 취급해야 하는지를 구분하는 데 도움을 준다.
단일 클립보드 항목만 붙여넣는 것을 지원하는 웹 앱은 첫 번째 클립보드 항목을 사용해야 한다.
둘 이상의 클립보드 항목을 붙여넣는 것을 지원하는 웹 앱은, 예를 들어 각 클립보드 항목의 내용을 미리 보여주고 사용자가 붙여넣을 항목을 선택할 수 있게 하는 사용자 인터페이스를 제공할 수 있다. 또한 앱은 붙여넣는 클립보드 항목의 MIME 타입을 열거하고, 앱별 알고리즘에 따라 앱에 가장 적합한 것을 선택할 것으로 기대된다. 또는 앱은 사용자에게 클립보드 항목을 붙여넣는 방법에 대한 옵션, 예컨대 "이미지로 붙여넣기" 또는 "서식 있는 텍스트 붙여넣기" 등을 제시할 수 있다.
ClipboardItem
객체는 관련된 클립보드 항목을 가지며, 이는 클립보드 항목이다.
ClipboardItem
객체는 관련된 types 배열을 가지며, 이는 FrozenArray<DOMString>이다.
ClipboardItem
객체는 관련된 읽기 시점의 클립보드 변경
횟수를 가지며,
이는 처음에는 null이다.
ClipboardItem
객체는 관련된 원본 시스템 클립보드
항목을 가지며, 이는 시스템 클립보드 항목 또는 null이고, 처음에는 null이다.
ClipboardItem
객체는 관련된 비정제 MIME 타입을 가지며, 이는 sequence<DOMString>이고,
처음에는 비어 있다.
ClipboardItem
객체는 관련된 해결자를 가진 표현을 가지며,
이는 문자열(getType()에
전달된
MIME
타입,
존재하는 경우 `"web "` 접두사를 포함함)에서 Promise<Blob>로의
맵이며,
처음에는 비어 있다. 각 항목은 해당 타입에 대한 OS 클립보드 읽기를 나타내며, 이는 완료되었거나
현재 진행 중이다.
Note: 이 맵은
getType()
으로부터 얻은 read()
ClipboardItem에서
같은 MIME 타입에 대한 동시
호출들이 단일 OS 클립보드 읽기를 공유하도록 보장한다. 첫 번째 호출은 보류 중인 Promise를
맵에 삽입하고 읽기를 시작한다. 같은 MIME 타입에 대한 이후 호출들은 시스템 클립보드를 다시 읽지 않고 기존 Promise를
반환한다.
read()로
ClipboardItem이
생성되면, 이는 데이터 스냅샷이 아니라 지연 fetcher로 동작한다. 그 types 배열은
read()
호출 시점에 시스템 클립보드에서 사용할 수
있는 형식을 반영하지만,
실제 페이로드 바이트는 getType()이
호출될 때까지 읽히지 않는다. read()
호출과 이후의 getType()
호출 사이에 시스템
클립보드 내용이 변경되면, getType()
호출은 거부된다. ClipboardItem(items, options)
생성자를 통해 직접 구성된 ClipboardItem은
이 동작의 대상이 아니다.
클립보드 항목
clipboardItem과 Realm realm이 주어졌을 때
ClipboardItem
객체를 생성하려면,
다음 단계를 실행한다:
-
clipboardItemObject를 realm으로 새로운
ClipboardItem으로 둔다. -
clipboardItemObject의 클립보드 항목을 clipboardItem으로 설정한다.
new ClipboardItem(items, options)
생성자 단계는 다음과 같다:
-
items가 비어 있으면,
TypeError를 던진다. -
options가 비어 있으면, options["presentationStyle"] = "unspecified"로 설정한다.
-
this의 클립보드 항목의 표현 스타일을 options["
presentationStyle"]로 설정한다. -
types를
DOMString의 목록으로 둔다. -
items의 각 (key, value)에 대해:
-
representation을 새 표현으로 둔다.
-
isCustom을 false로 둔다.
-
key가 `"web "` 접두사로 시작하면, 다음을 수행한다
-
`"web "` 접두사를 제거하고 남은 문자열을 key에 할당한다.
-
isCustom을 true로 설정한다
-
-
representation의 isCustom 플래그를 isCustom으로 설정한다.
-
mimeType을 key가 주어졌을 때 MIME 타입 파싱의 결과로 둔다.
-
mimeType이 failure이면,
TypeError를 던진다. -
this의 클립보드 항목의 표현 목록이 mimeType인 MIME 타입과 isCustom인 [representation/isCustom]을 가진 표현을 포함하면,
TypeError를 던진다.
위 단계는 사용자 에이전트가 잘 알고 있는 mime-types와, 작성자가 사용자 정의 타입으로 취급하려고 의도한 mime-types 사이의 충돌을 방지한다. 예를 들어, 작성자의 items 목록이 "text/html"에 대한 표현과 "web text/html"에 대한 표현을 모두 포함하는 것이 가능할 수 있다.
-
7.2.1. presentationStyle
presentationStyle
getter의 단계는 this의
clipboard item의 presentation style을 반환하는 것이다.
7.2.2. types
types
getter의 단계는 this의
types
array를 반환하는 것이다.
7.2.3. getType(type)
이 메서드는 아래 단계를 실행해야 한다:
-
isCustom을 false로 둔다.
-
type이 `"web "` 접두사로 시작하면:
-
`"web "` 접두사를 제거하고 남은 문자열을 type에 할당한다.
-
isCustom을 true로 설정한다.
-
-
mimeType을 type이 주어졌을 때 MIME 타입 파싱의 결과로 둔다.
-
mimeType이 failure이면,
TypeError를 던진다. -
p를 realm 안의 새 Promise로 둔다.
-
itemTypeList 안의 각 representation에 대해:
-
representation의 MIME 타입이 mimeType이고 representation의 isCustom이 isCustom이면:
-
this의 읽기 시점의 클립보드 변경 횟수가 null이 아니고, 현재 클립보드 변경 횟수가 this의 읽기 시점의 클립보드 변경 횟수와 같지 않으면, realm에서
"InvalidStateError"DOMException으로 p를 거부하고, p를 반환한다.Note: 이는 오래된 데이터가 절대 반환되지 않도록 보장한다.
read()가 호출된 이후 시스템 클립보드 내용이 변경된 경우, 현재 시스템 클립보드 상태에 해당하지 않는 데이터를 반환하는 대신 반드시 실패해야 한다.Note: null인 읽기 시점의 클립보드 변경 횟수는 이
ClipboardItem이read()에서 얻어진 것이 아니라 작성자가 직접 구성한 것임을 나타낸다(예:ClipboardItem(items, options)를 통해). 이 경우 데이터가 시스템 클립보드에서 비롯된 것이 아니므로 오래된 데이터 검사가 필요하지 않다. -
this의 읽기 시점의 클립보드 변경 횟수가 null이 아니면:
Note: 이 분기는
read()에서 얻은ClipboardItem들을 다루며, 이 경우 OS 클립보드 읽기는 이 지점까지 지연된다. 같은 MIME 타입에 대해getType()이 동시에 여러 번 호출되더라도 타입당 읽기가 최대 한 번만 발생하도록, 결과Promise는 정규화된 타입 문자열을 키로 하여 this의 resolver를 가진 표현 맵에 캐시된다. 따라서 `"text/html"`과 `"web text/html"`은 독립적으로 추적되는 반면, 같은 타입의 대소문자만 다른 표기 (예: `"text/HTML"`과 `"text/html"`)는 하나의 항목으로 합쳐진다.-
key를 mimeType의 essence로 둔다. isCustom이 true이면, key 앞에 `"web "`를 붙인다.
-
this의 resolver를 가진 표현[key]가 존재하면, this의 resolver를 가진 표현[key]를 반환한다.
-
this의 resolver를 가진 표현[key]를 p로 설정한다.
-
다음 단계를 병렬로 실행한다:
-
clipboardItem을 this의 원본 시스템 클립보드 항목으로 둔다.
-
clipboardItem이 null이면, realm의 전역 객체가 주어졌을 때 클립보드 태스크 소스에 전역 태스크를 큐에 넣어, realm에서
"InvalidStateError"DOMException으로 p를 거부한 다음, 이 단계를 중단한다. -
isCustom이 true이면:
-
mapName을 OS별 사용자 정의 맵 이름으로 둔다.
-
mapRepresentation을 clipboardItem의 시스템 클립보드 표현 목록 중 그 이름이 mapName인 시스템 클립보드 표현으로 둔다. 그러한 시스템 클립보드 표현이 없으면, realm의 전역 객체가 주어졌을 때 클립보드 태스크 소스에 전역 태스크를 큐에 넣어, realm에서
"NotFoundError"DOMException으로 p를 거부한 다음, 이 단계를 중단한다. -
webCustomFormatMapString을 mapRepresentation의 데이터에서 역직렬화된 JSON 문자열로 둔다.
-
osFormatName을 webCustomFormatMapString 안에서 mimeType이 직렬화된 값과 일치하는 키의 값으로 둔다.
-
osFormatName을 찾을 수 없으면, realm의 전역 객체가 주어졌을 때 클립보드 태스크 소스에 전역 태스크를 큐에 넣어, realm에서
"NotFoundError"DOMException으로 p를 거부한 다음, 이 단계를 중단한다.
-
-
그렇지 않으면, osFormatName을 mimeType이 주어졌을 때 OS별 잘 알려진 형식을 실행한 결과로 둔다.
-
clipboardRepresentation을 clipboardItem의 시스템 클립보드 표현 목록 중 그 이름이 osFormatName인 시스템 클립보드 표현으로 둔다. 그러한 시스템 클립보드 표현이 없으면, realm의 전역 객체가 주어졌을 때 클립보드 태스크 소스에 전역 태스크를 큐에 넣어, realm에서
"NotFoundError"DOMException으로 p를 거부한 다음, 이 단계를 중단한다. -
rawData를 clipboardRepresentation의 데이터로 둔다.
-
cleanData를 rawData의 복사본으로 둔다.
-
mimeType의 essence가 this의 비정제 MIME 타입 안에 있고, mimeType의 essence가 선택적 비정제 데이터 타입 목록 안에 있으면, 아무것도 하지 않는다.
-
그렇지 않고 mimeType의 essence가 "image/png"가 아니면, 사용자 에이전트는 cleanData를 정제해도 된다.
-
blob을
Blob으로 둔다. 그type은 mimeType이 직렬화된 값이고, 그 기반 바이트 시퀀스는 cleanData이다. -
realm의 전역 객체가 주어졌을 때, 클립보드 태스크 소스에 전역 태스크를 큐에 넣어 p를 blob으로 resolve한다.
-
Note: p가 settled되면, 이는 this의 resolver를 가진 표현 맵 안에 남는다. 같은 MIME 타입에 대한 이후
getType()호출은 시스템 클립보드를 다시 읽지 않고 캐시된 settledPromise를 반환한다. 그러나 위의 오래된 데이터 검사는 모든 호출에 여전히 적용된다. 즉,read()가 호출된 이후 시스템 클립보드가 변경되었다면, 이ClipboardItem에 대한 모든getType()호출은 이전에 캐시된 데이터에 대해서도"InvalidStateError"로 거부된다.-
p를 반환한다.
-
-
representationDataPromise를 representation의 데이터로 둔다.
-
representationDataPromise에 반응한다:
-
representationDataPromise가 값 v로 fulfilled되었다면:
-
representationDataPromise가 rejected되었다면:
-
realm에서
"NotFoundError"DOMException으로 p를 거부한다.
-
-
-
p를 반환한다.
-
-
-
realm에서
"NotFoundError"DOMException으로 p를 거부한다. -
p를 반환한다.
7.2.4. supports(type)
이 메서드는 아래 단계를 실행해야 한다:
-
type이 필수 데이터 타입 또는 선택적 데이터 타입에 포함되어 있으면 true를 반환한다.
-
그렇지 않으면 false를 반환한다.
7.3. Clipboard 인터페이스
typedef sequence <ClipboardItem >; [ClipboardItems SecureContext ,Exposed =Window ]interface :Clipboard EventTarget {Promise <ClipboardItems >read (optional ClipboardUnsanitizedFormats = {});formats Promise <DOMString >readText ();Promise <undefined >write (ClipboardItems );data Promise <undefined >writeText (DOMString ); };data dictionary {ClipboardUnsanitizedFormats sequence <DOMString >; };unsanitized
Clipboard
인터페이스의 일부 메서드는 여러 ClipboardItem
객체를 받거나 반환한다. 그러나 모든 플랫폼이 둘 이상의 클립보드 항목을 지원하는 것은 아니다. 그러한 플랫폼에서는 아래 알고리즘이
write()에
전달된 첫 번째 항목 이후의 모든 ClipboardItem
객체를 무시하며,
read()
및 readText()는
OS에서 하나의 클립보드 항목만 가져온다.
클립보드 항목들 객체는 sequence의 클립보드 항목들이다.
웹 작성자는 write(data)
메서드를 사용하여 시스템 클립보드에
콘텐츠를 쓰기 위해, ClipboardItem들의
배열인 data를 생성해야 한다.
read()는
시스템 클립보드 데이터의
내용을 나타내는 클립보드 항목들 객체에 대한
Promise를
반환한다.
unsanitized는
작성자가 선택적 비정제 데이터 타입으로 취급되기를 원하는 MIME 타입에 대응하는 DOMString들의
sequence이다.
unsanitized
옵션은 사용자 에이전트에서 지원되지 않을 수도 있다. 이 옵션이 허용되지 않을 수 있는 프라이버시 모드가 있을 수 있으므로, 웹 작성자는
unsanitized에
나열된 MIME 타입의 콘텐츠가 비정제 상태일 것이라고 가정해서는 안 된다.
클립보드 태스크 소스는 시스템 클립보드 데이터의 읽기 또는 쓰기에 대한 응답으로 트리거된다.
7.3.1. read(formats)
read(formats)
메서드는 다음 단계를 실행해야 한다:
-
p를 realm 안의 새 promise로 둔다.
-
formats가 비어 있지 않으면:
-
formats["
unsanitized"] 안의 각 format에 대해:-
format이 선택적 비정제 데이터 타입 안에 없으면, realm에서 format
"NotAllowedError"DOMException으로 p를 거부한다.
-
-
-
다음 단계를 병렬로 실행한다:
-
r을 클립보드 읽기 권한 확인을 실행한 결과로 둔다.
-
r이 false이면:
-
realm의 전역 객체가 주어졌을 때, 권한 태스크 소스에 전역 태스크를 큐에 넣어, realm에서
"NotAllowedError"DOMException으로 p를 거부한다. -
이 단계를 중단한다.
-
-
data를 시스템 클립보드 데이터로 둔다.
-
snapshotChangeCount를 현재 클립보드 변경 횟수로 둔다.
Note: 이 시점에서는 data의 이름(형식 식별자)만 열거된다. 각 표현의 기반 페이로드 바이트는
getType()이 호출될 때까지 읽히지 않는다. -
items를 sequence의 ordered map들로 둔다. 각 항목은 "item"(클립보드 항목)과 "originating"(시스템 클립보드 항목 또는 null) 키를 가진다.
-
data 안의 각 systemClipboardItem에 대해:
-
item을 새 클립보드 항목으로 둔다.
-
systemClipboardItem 안의 각 systemClipboardRepresentation에 대해:
-
mimeType을 systemClipboardRepresentation의 이름이 주어졌을 때 OS별 형식으로부터의 잘 알려진 MIME 타입 알고리즘을 실행한 결과로 둔다.
-
mimeType이 null이면, 이 루프를 계속한다.
-
representation을 새 표현으로 둔다.
-
representation의 MIME 타입을 mimeType으로 설정한다.
-
representation의 데이터를 realm 안의 새 promise로 설정한다.
Note: 이 표현에 대한 OS 클립보드 데이터는 작성자가 결과
ClipboardItem객체에서getType()을 호출할 때까지 가져오지 않는다. -
representation을 item의 표현 목록에 추가한다.
-
-
item의 표현 목록 크기가 0보다 크면, ordered map «[ "item" → item, "originating" → systemClipboardItem ]»을 items에 추가한다.
-
-
items의 크기가 > 0이면:
-
firstItem을 items[0]["item"]으로 둔다
-
firstItem이 주어졌을 때 웹 사용자 정의 형식 읽기 알고리즘을 실행한다.
-
-
그렇지 않으면:
-
customItem을 새 클립보드 항목으로 둔다.
-
customItem이 주어졌을 때 웹 사용자 정의 형식 읽기 알고리즘을 실행한다.
-
customItem의 표현 목록 크기가 0보다 크면, ordered map «[ "item" → customItem, "originating" → null ]»을 items에 추가한다.
-
-
realm의 전역 객체가 주어졌을 때, 클립보드 태스크 소스에 전역 태스크를 큐에 넣어, 아래 단계를 수행한다:
-
clipboardItems를 sequence<
ClipboardItem>로 둔다. -
items의 각 ordered map entry에 대해:
-
clipboardItem을 entry["item"]과 realm이 주어졌을 때 ClipboardItem 객체 생성의 단계를 실행한 결과로 둔다.
-
clipboardItem의 읽기 시점의 클립보드 변경 횟수를 snapshotChangeCount로 설정한다.
-
clipboardItem의 원본 시스템 클립보드 항목을 entry["originating"]으로 설정한다.
-
formats가 비어 있지 않으면, clipboardItem의 비정제 MIME 타입을 formats["
unsanitized"]로 설정한다. -
clipboardItem을 clipboardItems에 추가한다.
-
-
p를 clipboardItems로 resolve한다.
-
-
-
p를 반환한다.
// clipboard.read()는 타입 메타데이터만 있는 ClipboardItems를 반환한다. // 이 시점에서는 OS 클립보드 데이터를 읽지 않는다. const items= await navigator. clipboard. read(); // getType()이 호출될 때, 여기서 OS 클립보드 읽기가 지연 수행된다. const textBlob= await items[ 0 ]. getType( "text/plain" ); const text= await ( new Response( textBlob)). text();
7.3.2. readText()
readText()
메서드는 다음 단계를 실행해야 합니다:
-
p를 realm 안의 새 promise로 둔다.
-
다음 단계를 병렬로 실행한다:
-
r을 클립보드 읽기 권한 확인을 실행한 결과로 둔다.
-
r이 false이면:
-
realm의 전역 객체가 주어졌을 때, 권한 태스크 소스에 전역 태스크를 큐에 넣어, realm에서
"NotAllowedError"DOMException으로 p를 거부한다. -
이 단계를 중단한다.
-
-
data를 시스템 클립보드 데이터의 복사본으로 둔다.
일부 OS는 여러 클립보드를 포함한다(예: Linux, "primary", "secondary", "selection"). 이들 중 어느 데이터에서 읽는지 정의하라.
-
realm의 전역 객체가 주어졌을 때, 클립보드 태스크 소스에 전역 태스크를 큐에 넣어, 아래 단계를 수행한다:
-
data 안의 각 systemClipboardItem에 대해:
-
systemClipboardItem 안의 각 systemClipboardRepresentation에 대해:
-
mimeType을 systemClipboardRepresentation의 이름이 주어졌을 때 OS별 형식으로부터의 잘 알려진 MIME 타입 알고리즘을 실행한 결과로 둔다.
-
mimeType이 null이면, 이 루프를 계속한다.
-
representation을 새 표현으로 둔다.
-
representation의 MIME 타입 essence가 "text/plain"이면:
-
representation의 MIME 타입을 mimeType으로 설정한다.
-
representationDataPromise를 representation의 데이터로 둔다.
-
representationDataPromise에 반응한다:
-
representationDataPromise가 값 v로 fulfilled되었다면:
-
representationDataPromise가 rejected되었다면:
-
realm에서
"NotFoundError"DOMException으로 p를 거부한다. -
p를 반환한다.
-
-
-
-
-
-
realm에서
"NotFoundError"DOMException으로 p를 거부한다. -
p를 반환한다.
-
-
navigator. clipboard. readText(). then( function ( data) { console. log( "Your string: " , data); });
7.3.3. write(data)
write(data)
메서드는 다음 단계를 실행해야 한다:
-
p를 realm 안의 새 promise로 둔다.
-
다음 단계를 병렬로 실행한다:
-
r을 클립보드 쓰기 권한 확인을 실행한 결과로 둔다.
clipboard-write는 https://github.com/w3c/clipboard-apis/pull/164에서 제거되었다.
-
r이 false이면:
-
realm의 전역 객체가 주어졌을 때, 권한 태스크 소스에 전역 태스크를 큐에 넣어, realm에서
"NotAllowedError"DOMException으로 p를 거부한다. -
이 단계를 중단한다.
-
-
realm의 전역 객체가 주어졌을 때, 클립보드 태스크 소스에 전역 태스크를 큐에 넣어, 아래 단계를 수행한다:
-
dataList를 sequence<
ClipboardItem>로 둔다. -
data의 크기가 1보다 크고, 현재 운영 체제가 시스템 클립보드에서 여러 네이티브 클립보드 항목을 지원하지 않으면, data[0]을 dataList에 추가하고, 그렇지 않으면 dataList를 data로 설정한다.
data가 여러 항목을 포함하고 운영 체제가 여러 네이티브 클립보드 항목을 지원하는 경우, 현재 알고리즘은 해당 항목들을 한꺼번에 쓰는 대신 순서대로 시스템 클립보드에 쓴다.
-
dataList 안의 각 clipboardItem에 대해:
-
clipboardItem의 클립보드 항목의 표현 목록 안의 각 representation에 대해:
-
representationDataPromise를 representation의 데이터로 둔다.
-
representationDataPromise에 반응한다:
-
representationDataPromise가 값 v로 fulfilled되었다면:
-
representationDataPromise가 rejected되었다면:
-
realm에서
"NotAllowedError"DOMException으로 p를 거부한다. -
이 단계를 중단한다.
-
-
-
-
itemList 안의 각 blob에 대해:
-
type을 blob의
type으로 둔다. -
type이 필수 데이터 타입 또는 선택적 데이터 타입 목록 안에 없으면, realm에서
"NotAllowedError"DOMException으로 p를 거부하고 이 단계를 중단한다. -
cleanItem을 blob의 선택적으로 정제된 복사본으로 둔다.
-
정제가 시도되었으나 성공적으로 완료되지 않았다면, 아래 단계를 따른다:
-
realm에서
"NotAllowedError"DOMException으로 p를 거부한다. -
이 단계를 중단한다.
-
-
cleanItem을 cleanItemList에 추가한다.
-
-
cleanItemList와 option으로 blob 및 옵션을 클립보드에 쓰기를 실행한다.
-
-
p를 resolve한다.
-
-
p를 반환한다.
var data= [ new ClipboardItem({ "text/plain" : Promise. resolve( new Blob([ "Text data" ], { type: "text/plain" })) })]; navigator. clipboard. write( data). then( function () { console. log( "Copied to clipboard successfully!" ); }, function () { console. error( "Unable to write to clipboard. :-(" ); });
7.3.4. writeText(data)
writeText(data)
메서드는 다음 단계를 실행해야 한다:
-
p를 realm 안의 새 promise로 둔다.
-
다음 단계를 병렬로 실행한다:
-
r을 클립보드 쓰기 권한 확인을 실행한 결과로 둔다.
clipboard-write는 https://github.com/w3c/clipboard-apis/pull/164에서 제거되었다.
-
r이 false이면:
-
realm의 전역 객체가 주어졌을 때, 권한 태스크 소스에 전역 태스크를 큐에 넣어, realm에서
"NotAllowedError"DOMException으로 p를 거부한다. -
이 단계를 중단한다.
-
-
realm의 전역 객체가 주어졌을 때, 클립보드 태스크 소스에 전역 태스크를 큐에 넣어, 아래 단계를 수행한다:
-
textBlob를 다음과 같이 생성된 새
Blob으로 둔다:type속성은 "text/plain;charset=utf-8"로 설정되고, 그 기반 바이트 시퀀스는 data의 UTF-8 인코딩으로 설정된다.Note: Windows에서는 textBlob를 생성하기 전에 data 안의 `\n` 문자를 `\r\n`으로 바꾼다.
-
textBlob를 itemList에 추가한다.
-
option을 "unspecified"로 설정한다.
-
itemList와 option으로 blob 및 옵션을 클립보드에 쓰기를 실행한다.
-
p를 resolve한다.
-
-
p를 반환한다.
await navigator. clipboard. writeText( "Howdy, partner!" );
8. 클립보드 동작
이 섹션은 클립보드 동작과 이벤트 디스패치 처리 모델을 정의합니다.
각 클립보드 동작은 스크립트-트리거됨 및 스크립트-클립보드-접근-허용이라는 두 개의 플래그를 가집니다.
스크립트-트리거됨
플래그는 동작이 스크립트로 인해 실행될 때(예: document.execCommand() 호출) 설정됩니다.
클립보드와 상호작용하는 향후 스크립팅 API도 이 플래그를 사용해야 하며,
스크립트-트리거됨 플래그가 올바르게
설정되어야 합니다.
스크립트-클립보드-접근-허용 플래그는 다음과 같이 설정됩니다:
-
동작이 복사 또는 잘라내기이고, 스크립트 스레드가 클립보드 수정 허용이면,
-
동작의 스크립트-클립보드-접근-허용 플래그를 설정한다
-
-
동작이 붙여넣기이고, 스크립트 스레드가 클립보드 읽기 허용이면,
-
동작의 스크립트-클립보드-접근-허용 플래그를 설정한다.
-
8.1. 복사 동작
복사 동작은 다음 단계로 구성됩니다:
-
script-triggered 플래그가 설정되어 있으면,
-
script-may-access-clipboard 플래그가 설정되어 있지 않으면,
-
복사 작업에서 false를 반환하고, 이 알고리즘을 종료합니다.
-
-
-
이벤트가 취소되지 않았다면,
-
선택한 내용(있는 경우)을 클립보드에 복사합니다. 구현체는 웹 페이지에서 내용이 선택되었을 때 대체 text/html 및 text/plain 클립보드 포맷을 생성하는 것이 권장됩니다.
-
"clipboardchange"라는 이름의
clipboardchange클립보드 이벤트를 발생시킵니다.
-
-
그렇지 않고 이벤트가 취소되었다면,
-
클립보드에 내용 쓰기 알고리즘을 호출합니다. 이때
DataTransferItemList리스트 items와 clear-was-called 플래그, types-to-clear 리스트를 전달합니다.
-
-
복사 작업에서 true를 반환합니다.
8.2. 잘라내기 동작
잘라내기 동작은 다음 단계로 구성됩니다:
-
script-triggered 플래그가 설정되어 있다면,
-
script-may-access-clipboard 플래그가 설정 해제되어 있다면,
-
잘라내기 작업에서 false를 반환하고, 이 알고리즘을 종료합니다.
-
-
-
이 이벤트가 취소되지 않았다면,
-
선택 영역이 편집 가능한 컨텍스트 내에서 잘라내기가 활성화된 상태라면,
-
선택된 내용(있는 경우)을 클립보드에 복사합니다. 구현체는 웹 페이지에서 내용이 선택되었을 때 대체 text/html 및 text/plain 클립보드 포맷을 생성하는 것이 권장됩니다.
-
문서에서 해당 선택 영역의 내용을 제거하고 선택 영역을 축소합니다.
-
"clipboardchange"라는 이름의
clipboardchange클립보드 이벤트를 발생시킵니다. -
변경으로 인해 발생해야 하는 모든 이벤트를 큐에 넣어 발생시키십시오. 자세한 내용은 § 5.3 다른 스크립트 및 이벤트와의 통합을 참조하세요.
-
-
그렇지 않고 선택 영역이 없거나, 컨텍스트가 편집 가능하지 않으면,
-
false를 반환합니다.
-
-
-
그 외에, 만약 이벤트가 취소되었다면,
-
클립보드에 내용 쓰기 알고리즘을 호출합니다. 이때
DataTransferItemList리스트 items와, clear-was-called 플래그, types-to-clear 리스트를 넘깁니다. -
"clipboardchange"라는 이름의
clipboardchange클립보드 이벤트를 발생시킵니다.
-
-
잘라내기 작업에서 true를 반환합니다.
8.3. 붙여넣기 동작
붙여넣기 동작에서 스크립트-클립보드-접근-허용 플래그는 어떤 사이트나 앱이 클립보드에서 읽을 수 있는지 결정하기 위한 구현체별 권한 메커니즘에 따라 달라집니다. 붙여넣기 동작이 스크립트로 트리거될 때, 구현체는 사용자의 허락 없이 클립보드 내용을 노출해서는 안 됩니다. 권한이 미리 부여되지 않은 경우, 권한 프롬프트에는 스크립트 스레드에 연결된 문서의 호스트명이 반드시 포함되어야 합니다.
붙여넣기 동작은 다음 단계로 구성됩니다:
-
스크립트-트리거됨 플래그가 설정되어 있으면,
-
스크립트-클립보드-접근-허용 플래그가 설정되어 있지 않으면,
-
붙여넣기 동작에서 false를 반환하고, 알고리즘을 종료한다
-
-
-
이 이벤트가 취소되지 않았으면,
-
editable context에서 붙여넣기가 허용된 선택 영역이나 커서가 존재하면,
-
클립보드에서 찾은 가장 적합한 콘텐츠(있는 경우)를 해당 컨텍스트에 삽입한다.
-
수정으로 인해 발생해야 하는 이벤트들을 큐에 추가한다. 자세한 내용은 § 5.3 다른 스크립트 및 이벤트와의 통합을 참고한다.
-
-
그렇지 않으면
-
false를 반환한다
-
-
-
그렇지 않고 이벤트가 취소되었다면
-
false를 반환한다
-
-
동작에서 true를 반환한다
9. Permissions API 연동
[permissions] API는 웹사이트가 강력한 기능(예: 클립보드)에 접근할 수 있는 통합 방식을 제공합니다. 웹사이트는 사용자의 권한을 요청하고, 어떤 권한을 가지고 있는지 조회할 수 있습니다.
클립보드의 경우, 하나의 권한이 정의되어 있습니다: "clipboard-write"
참고: 클립보드 권한은 현재 비동기 클립보드 API에만 적용됩니다. 향후 이 명세의 버전에서는 다른 클립보드 상호작용에도 이 권한이 적용될 수 있습니다.
다음과 같이 클립보드 권한은 강력한 기능이며, 권한 관련 알고리즘과 타입은 다음과 같이 정의됩니다:
- permission descriptor type
-
dictionary :ClipboardPermissionDescriptor PermissionDescriptor {boolean =allowWithoutGesture false ; };
클립보드 권한은 4가지가 있습니다:
-
{ name: "clipboard-write", allowWithoutGesture: false }
-
{ name: "clipboard-write", allowWithoutGesture: true }
관계는 다음과 같습니다:
-
{ "clipboard-write" + true }는{ "clipboard-write" + false }보다 더 강력합니다.
사용자 에이전트는 반드시 명세서에 설명된 대로 ClipboardPermissionDescriptor
를 지원해야 하지만,
기본 설정과 사용자에게 어떻게 노출하는지는 완전히 제어할 수 있습니다.
-
{ "clipboard-write" + false }는 사용자 제어용으로 노출됨 -
{ "clipboard-write" + true }는 항상거부됨
9.1. 클립보드 읽기 권한
9.1.1. 클립보드 읽기 권한 확인
-
hasGesture를 relevant global object가 this에서 일시적 활성화(transient activation)를 가지고 있으면 true, 그렇지 않으면 false로 한다.
-
hasGesture이면,
-
현재 스크립트가 사용자 에이전트나 OS가 생성한 "Paste" 요소와의 사용자 상호작용 결과로 실행되고 있다면 true를 반환한다.
-
-
false를 반환한다.
9.2. 클립보드 쓰기 권한
9.2.1. 클립보드 쓰기 권한 확인
-
writeWithoutGesture를 permission state({ name: "clipboard-write", allowWithoutGesture: true } 권한 기준)로 한다.
-
writeWithoutGesture가
granted이면 true를 반환한다. -
hasGesture를 this의 관련 글로벌 객체에 일시적 활성화(transient activation)가 있으면 true로, 그렇지 않으면 false로 둡니다.
-
hasGesture이면,
-
현재 스크립트가 사용자 에이전트나 OS가 생성한 "cut" 또는 "copy" 요소와의 사용자 상호작용 결과로 실행되고 있다면 systemCopy를 true로 한다.
-
systemCopy가 true이면 true를 반환한다.
-
request permission to use({ name: "clipboard-write", allowWithoutGesture: false } 권한 기준) 결과를 반환한다.
참고: 사용자 에이전트는 더 강력한 권한을 요청하여 이 권한을 암묵적으로 업데이트할 수도 있습니다.
-
-
request permission to use({ name: "clipboard-write", allowWithoutGesture: true } 권한 기준) 결과를 반환한다.
10. 보안 고려사항
저자가 사용자가 복사하는 내용을 변경하거나, 선택된 적이 없는 내용을 자동으로 복사하거나, 정보 붙여넣기를 제한 없이 호출할 수 있도록 하면 다양한 보안 문제가 발생할 수 있습니다.
예시 시나리오:
-
사용자가 링크를 선택하고 복사했으나, 실제로 다른 링크가 클립보드에 복사됨. 이는 붙여넣기 시 예상치 못한 결과에서 피싱 공격 시도까지 이어질 수 있습니다.
-
(Self-XSS) 셸 명령어나 실행 가능한 스크립트가 클립보드에 삽입되어 사용자가 붙여넣은 후 실행할 수 있습니다.
-
OS의 이미지 처리 코드의 버그를 악용하도록 특별히 제작된 이미지를 클립보드에 쓸 수 있습니다.
10.1. HTML 및 멀티파트 데이터 붙여넣기
이 섹션은 규범적이지 않습니다.
서식 있는 데이터나 멀티파트 데이터를 붙여넣는 데에는 특정 보안 위험이 있습니다.
-
사용자가 보이지 않는 데이터를 인지하지 못한 채 붙여넣을 수 있습니다. 예를 들어, 마크업에 <input type="hidden"> 태그나 HTML 주석이 포함된 경우. 이러한 숨겨진 데이터에는 민감한 정보가 포함될 수 있습니다.
-
사용자가 신뢰하는 페이지에 악성 JavaScript를 붙여넣을 수 있습니다.
-
구현체가 사용자가 공개를 의도하지 않은 로컬 파일에 대한 스크립트 접근을 허용할 수 있습니다.
어떤 정책을 사용할지 결정하기 위해 고려하는 요소는 다음과 같습니다:
-
붙여넣는 데이터의 출처
-
참조된 이미지 등 부분 데이터의 출처
-
실행 중인 스크립트의 출처
각 시나리오와 적용 가능한 보안 정책 개요:
| 데이터 출처 | 스크립트 출처 | 규칙 |
|---|---|---|
| 온라인 소스에서 기원 | 데이터와 동일 | HTML을 정제하지 않음. 로컬 파일 접근 불가. |
| 다른 출처 | 콘텐츠 선택적 정제. 로컬 파일 접근 불가. | |
| 로컬 애플리케이션에서 기원 | 상관 없음 | HTML을 정제하지 않음. 로컬 파일 접근 허용 |
일부 구현체는 서식 있는 텍스트 붙여넣기 관련 위험을 완화하기 위해, 기본적으로 SCRIPT 요소나 javascript: 링크 등 잠재적으로 악성인 콘텐츠를 제거하지만, paste 이벤트 핸들러에서는 원본, 비정제 데이터를 처리할 수 있도록 허용합니다.
10.2. 일반 보안 정책
구현체는 온라인에서 참조된 리소스를 다운로드하거나, 그 내용을 files
리스트나 DataTransferItemList
에 노출해서는 안 됩니다.
클립보드 데이터가 로컬 애플리케이션 출신이 아니라면, 구현체는 참조된 로컬 파일에 대한 접근을 허용해서는 안 됩니다. 예를 들면, 데이터에 <img src="file://localhost/example.jpg">가 포함되어 있고 데이터 출처가 온라인 리소스라면, 구현체는 clipboardData.items 리스트에 example.jpg 항목을 추가해서는 안 됩니다.
10.3. 이미지 트랜스코딩
악성 이미지 데이터가 클립보드에 저장되는 것을 방지하기 위해, 이미지 데이터를 안전한 버전으로 트랜스코딩할 수 있습니다. 이를 통해 웹사이트가 다른 애플리케이션의 보안 취약점을 악용하는 것을 막을 수 있습니다.
구현체는 클립보드에서 읽는 이미지를 트랜스코딩해서는 안 됩니다. 트랜스코딩하면 이미지의 물리적 해상도와 같은 중요한 메타데이터가 손실될 수 있습니다. 이는 <input type=file> 등 웹사이트에서 이미지를 공유하는 다른 방식과도 일치합니다.
10.4. 방해 고려사항
스크립트는 DataTransfer
API를 사용하여 복사 및 잘라내기 이벤트에서 시스템 클립보드의 데이터를 변경함으로써 사용자를 혼란스럽게 하거나 괴롭힐 수 있습니다. 이 명세서는 이런 방해를 방지하려고 하지 않지만, 구현체는
추가 제한을 둘 수 있습니다.
구현체는 스크립트가 클립보드에 과도한 양의 데이터를 저장하려는 시도를 우아하게 처리해야 합니다.
11. 프라이버시 고려사항
이 API들은 사용자의 클립보드 데이터에 접근할 수 있으므로, 이름, 주소, 비밀번호 등 개인정보(PII)가 클립보드에 저장될 수 있어 심각한 프라이버시 문제가 있습니다.
일반적으로, 사용자 에이전트는 신뢰되지 않은 스크립트가 이러한 API를 통해 사용자의 클립보드 데이터를 무제한으로 접근하지 못하도록 반드시 보장해야 합니다.
11.1. 프라이버시와 클립보드 이벤트 API
클립보드 이벤트 API는 클립보드 이벤트 핸들러 컨텍스트에서 실행되는 스크립트가 시스템 클립보드의 복사본에 접근하고, 클립보드에 쓰이는 데이터를 수정할 수 있도록 허용합니다.
사용자 에이전트는 클립보드 이벤트 API를 통해 접근하는 데이터 보안을 위해 다음 요구사항을 인지해야 합니다:
-
DataTransfer인터페이스를 구현하여 클립보드 데이터를 반환하는 객체는 해당 ClipboardEvent 이벤트 핸들러 외부에서는 노출되어서는 안 됩니다. -
스크립트가 ClipboardEvent 이벤트 핸들러 외부에서 사용하기 위해 DataTransfer 인터페이스를 구현한 객체의 참조를 저장한 경우, 그 모든 메서드는 예상된 컨텍스트 외부에서는 동작하지 않아야(no-op) 합니다.
-
구현체는 스크립트가 합성 클립보드 이벤트를 생성해서 실제 클립보드 데이터에 접근하는 것을 허용해서는 안 됩니다 (사용자가 직접 설정한 경우는 예외).
클립보드 이벤트 API는 클립보드 권한에 적용되지 않지만, 사용자 에이전트는 사용자가 이 API를 비활성화하거나 특정 사이트에만 접근을 허용하도록 설정할 수 있는 방법을 제공할 수 있습니다.
11.2. 프라이버시와 비동기 클립보드 API
비동기 클립보드 API는 강력한 기능입니다. 이벤트 핸들러 컨텍스트에 국한되지 않고, 모든 스크립트가 클립보드 데이터에 접근할 수 있으며, 사용자 제스처 없이도 데이터에 접근할 수 있습니다.
남용을 막기 위해, 이 API는 문서가 포커스를 가지고 있을 때만 사용할 수 있어야 합니다.
11.2.1. 프라이버시와 클립보드 권한
클립보드 권한은 이 API 접근을 제한하지만, 사용자 에이전트는 권한의 기본값과 어떤 권한 설정을 사용자가 조정할 수 있을지 선택할 수 있습니다. 예를 들어, 사용자 에이전트는 사용자 제스처가 있는 경우에만 비동기 클립보드 API 접근을 허용하고, 제스처 없는 스크립트 요청은 항상 거부할 수 있습니다.
사용자 에이전트는 사용자가 권한을 부여한 후 권한이 자동으로 만료되도록 선택할 수 있습니다. 예를 들어, 권한 만료 조건은 다음과 같습니다:
-
권한 부여 후 일정 시간이 지나면
-
사용자가 사이트를 마지막으로 방문한 후 일정 시간이 지나면
-
사용자가 페이지를 벗어나면
11.3. 기타 프라이버시 우려
사용자 에이전트가 document.execCommand("paste")를 통해 클립보드 데이터를 읽을 수 있게 허용하는 경우, 반드시 사용자가 명시적으로 접근을 허용했는지
확인해야 합니다.
12. 감사의 글
이 섹션은 규범적이지 않습니다.
에디터들은 이전 에디터들의 기여를 인정합니다. 그들은 이 명세가 지금의 형태에 이르기까지 다양한 회의와 메일링 리스트 논의를 통해 발전시켜 주었습니다.
-
Hallvord R. M. Steen
에디터들은 또한 Microsoft의 Data Transfer 기능 문서 [MICROSOFT-CLIP-OP]와 [HTML5] 명세의 이전 초안에 지적 빚을 졌음을 인정합니다. 또한 Paul Libbrecht의 "safe copy and paste" 초안에도 감사드립니다 (이 초안은 현재 웹에서 제공되지 않습니다).
마지막으로 다음 분들의 기여에 감사드립니다:
Adam Barth, Shawn Carnell, Daniel Cheng, Daniel Dardailler, Domenic Denicola, Al Gilman, James Graham, James Greene, Ian Hickson, Darwin Huang, Lachlan Hunt, Philip Jägenstedt, Anne van Kesteren, Marijn Kruisselbrink, Aaron Leventhal, Jim Ley, Paul Libbrecht, "Martijn", Glenn Maynard, Chris Mills, ms2ger, Ryosuke Niwa, Robert O’Callahan, Dave Poehlman, "ROBO Design", Janina Sajka, Rich Schwerdtfeger, Jonas Sicking, Maciej Stachowiak, Mihai Sucan, Dmitry Titov, Ojan Vafai, Tarquin Wilton-Jones, Tom Wlodkowski, Bo Cupp, mbrodesser 그리고 Boris Zbarsky.
부록 A: 알고리즘
클립보드에 콘텐츠 쓰기
- 입력
-
items :
DataTransferItemList클립보드에 쓸 아이템 리스트clear-was-called : boolean 값
types-to-clear : 리스트
- 출력
-
없음
-
items 리스트가 비어 있지 않으면,
-
클립보드를 비운다
-
리스트의 각 파트에 대해,
-
데이터 타입이 text/plain이면,
-
OS 및 로캘 관례에 따라 인코딩이 올바른지 확인
-
플랫폼 관례에 따라 줄바꿈을 정규화
-
OS 클립보드 포맷 설명에 맞게 텍스트를 클립보드에 넣는다
-
-
그 외, 데이터가 필수 데이터 타입 리스트에 포함된 타입이면,
-
OS 클립보드 포맷 설명에 맞게 파트를 클립보드에 넣는다
-
-
그 외의 경우
-
-
-
그 외, items 리스트가 비어 있다면, 아래와 같이 클립보드를 비울지 결정한다:
블롭과 옵션을 클립보드에 기록하기
-
items 안의 각 item에 대해:
-
formatString을 item의
type이 주어졌을 때 OS별 잘 알려진 형식을 실행한 결과로 둔다. -
formatString이 비어 있으면 아래 단계를 따른다:
-
webCustomFormatString을 item의
type으로 둔다. -
webCustomFormat을 빈
type으로 둔다. -
webCustomFormatString이 `"web "` 접두사로 시작하면, `"web "` 접두사를 제거하고 남은 문자열을 webMimeTypeString에 저장한다.
-
webMimeType을 webMimeTypeString이 주어졌을 때 MIME 타입 파싱의 결과로 둔다.
-
webMimeType이 failure이면, 모든 단계를 중단한다.
-
item의
type을 webCustomFormat으로 설정한다. -
webCustomFormat을 webCustomFormats에 추가한다.
-
-
payload를 item의 기반 바이트 시퀀스에 대한 UTF-8 디코딩 결과로 둔다.
-
formatString을 네이티브 클립보드 형식으로 사용하여 payload와 presentationStyle을 시스템 클립보드에 삽입한다.
일부 OS는 여러 클립보드를 포함한다(예: Linux, "primary", "secondary", "selection"). 이들 중 어느 곳에 데이터가 쓰이는지 정의하라.
-
-
webCustomFormats가 주어졌을 때 웹 사용자 정의 형식 쓰기를 실행한다.
OS별 알려진 포맷
- 입력
-
mimeType,
type - 출력
-
wellKnownFormat, 플랫폼별 문자열 타입. Mac에서는 NSPasteboardType이고, Windows에서는 LPCWSTR이며 Linux에서는 const char*이다.
Windows의 경우 https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats 및 https://docs.microsoft.com/en-us/windows/win32/dataxchg/about-atom-tables?redirectedfrom=MSDN 참조. Mac의 경우 https://developer.apple.com/documentation/appkit/nspasteboardtype 참조.
-
wellKnownFormat을 빈 문자열로 둔다.
-
mimeType의 essence가 "text/plain"이면,
Windows에서는 아래에 설명된 규칙을 따른다:
-
CF_UNICODETEXT를 wellKnownFormat에 할당한다.
MacOS에서는 아래에 설명된 규칙을 따른다:
-
NSPasteboardTypeString을 wellKnownFormat에 할당한다.
Linux, ChromeOS 및 Android에서는 아래에 설명된 규칙을 따른다:
-
"text/plain"을 wellKnownFormat에 할당한다.
-
-
그렇지 않고, mimeType의 essence가 "text/html"이면,
Windows에서는 아래에 설명된 규칙을 따른다:
-
CF_HTML을 wellKnownFormat에 할당한다.
MacOS에서는 아래에 설명된 규칙을 따른다:
-
NSPasteboardTypeHTML을 wellKnownFormat에 할당한다.
Linux, ChromeOS 및 Android에서는 아래에 설명된 규칙을 따른다:
-
"text/html"을 wellKnownFormat에 할당한다.
-
-
그렇지 않고, mimeType의 essence가 "image/png"이면,
Windows에서는 아래에 설명된 규칙을 따른다:
-
"PNG"를 wellKnownFormat에 할당한다.
MacOS에서는 아래에 설명된 규칙을 따른다:
-
NSPasteboardTypePNG를 wellKnownFormat에 할당한다.
Linux, ChromeOS 및 Android에서는 아래에 설명된 규칙을 따른다:
-
"image/png"를 wellKnownFormat에 할당한다.
-
-
그렇지 않고, mimeType의 essence가 "image/svg+xml"이면,
Windows에서는 아래에 설명된 규칙을 따른다:
-
CFSTR_MIME_SVG_XML을 wellKnownFormat에 할당한다.
MacOS에서는 아래에 설명된 규칙을 따른다:
-
UTTypeSVG를 wellKnownFormat에 할당한다.
Linux, ChromeOS 및 Android에서는 아래에 설명된 규칙을 따른다:
-
"image/svg+xml"을 wellKnownFormat에 할당한다.
-
-
wellKnownFormat을 반환한다.
OS별 포맷에서 알려진 MIME 타입
- 입력
-
osFormatName : 플랫폼별 문자열 타입 (Mac: NSPasteboardType, Windows: LPCWSTR, Linux: const char*)
- 출력
-
mimeType : MIME type
Windows: https://docs.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats 및 https://docs.microsoft.com/en-us/windows/win32/dataxchg/about-atom-tables?redirectedfrom=MSDN Mac: https://developer.apple.com/documentation/appkit/nspasteboardtype
Windows에서는 다음과 같이:
-
osFormatName이 "UnicodeText"면 mimeTypeString을 "text/plain"으로 설정
-
그 외, osFormatName이 "HTML Format"이면 mimeTypeString을 "text/html"로 설정
-
그 외, osFormatName이 "PNG"이면 mimeTypeString을 "image/png"로 설정
-
그 외, osFormatName이 CFSTR_MIME_SVG_XML이면 mimeTypeString을 "image/svg+xml"로 설정
MacOS에서는 다음과 같이:
-
osFormatName이 NSPasteboardTypeString이면 mimeTypeString을 "text/plain"으로 설정
-
그 외, osFormatName이 NSPasteboardTypeHTML이면 mimeTypeString을 "text/html"로 설정
-
그 외, osFormatName이 NSPasteboardTypePNG이면 mimeTypeString을 "image/png"로 설정
-
그 외, osFormatName이 UTTypeSVG이면 mimeTypeString을 "image/svg+xml"로 설정
Linux, ChromeOS, Android에서는 다음과 같이:
-
osFormatName이 "text/plain"이면 mimeTypeString을 "text/plain"으로 설정
-
그 외, osFormatName이 "text/html"이면 mimeTypeString을 "text/html"로 설정
-
그 외, osFormatName이 "image/png"이면 mimeTypeString을 "image/png"로 설정
-
그 외, osFormatName이 "image/svg+xml"이면 mimeTypeString을 "image/svg+xml"로 설정
-
mimeType을 MIME 타입 파싱(mimeTypeString 기준) 결과로 한다.
-
mimeType을 반환한다.
웹 커스텀 포맷 읽기
- 입력
-
item, 클립보드 항목
-
webCustomFormatMap을 OS별 사용자 정의 맵 이름으로 둔다.
-
시스템 클립보드에서 webCustomFormatMap을 읽는다.
-
webCustomFormatMap이 비어 있으면, item을 반환한다.
-
webCustomFormatMapString을 webCustomFormatMap에서 역직렬화된 JSON 문자열로 둔다.
Note: webCustomFormatMap에서 콘텐츠를 역직렬화하려면 JSON 리더가 필요하다.
-
webCustomFormatMapString 안의 각 (key, value)에 대해:
-
mimeType을 key가 주어졌을 때 MIME 타입 파싱의 결과로 둔다.
-
mimeType이 failure이면, 루프를 계속한다.
-
representation을 새 표현으로 둔다.
-
representation의 MIME 타입을 mimeType으로 설정한다.
-
representation의 isCustom 플래그를 true로 설정한다.
-
representation의 데이터를 새 promise로 설정한다.
Note: 이 웹 사용자 정의 형식에 대한 OS 클립보드 데이터는 작성자가 결과
getType()을ClipboardItem객체에서 호출할 때까지 가져오지 않는다. -
representation을 item의 표현 목록에 추가한다.
-
웹 커스텀 포맷 쓰기
-
idx를 0으로 초기화된 숫자로 둔다.
-
webCustomFormatMap을 OS별 사용자 정의 맵 이름으로 둔다.
-
webCustomFormatMapString을 빈 JSON 문자열로 둔다.
-
items 안의 각 item에 대해:
-
webCustomFormat을 OS별 사용자 정의 이름으로 둔다.
-
webCustomFormatIdx를 idx를 webCustomFormat에 추가한 결과로 둔다.
-
item의
type을 키로, webCustomFormatIdx를 값으로 하여 JSON serializer를 사용해 webCustomFormatMapString에 삽입한다.Note: 콘텐츠를 webCustomFormatMapString으로 직렬화하려면 JSON writer가 필요하다.
-
webCustomFormatIdx를 형식으로 사용하여 item을 시스템 클립보드에 삽입한다.
-
idx를 증가시킨다.
-
idx가 100보다 크면, 이 루프에서 빠져나온다.
-
-
webCustomFormatMap을 형식으로 사용하여 webCustomFormatMapString을 시스템 클립보드에 삽입한다.
OS별 커스텀 포맷 맵 이름
- 출력
-
webCustomFormatMap, 문자열
Windows에서는 다음과 같이:
-
webCustomFormatMap에 "Web Custom Format Map" 할당.
-
webCustomFormatMap 반환.
MacOS에서는 다음과 같이:
-
webCustomFormatMap에 "org.w3.web-custom-format.map" 할당.
-
webCustomFormatMap 반환.
Linux, ChromeOS, Android에서는 다음과 같이:
-
webCustomFormatMap에 "application/web;type=\"custom/formatmap\"" 할당.
-
webCustomFormatMap 반환.
운영체제별 커스텀 이름
- 출력
-
webCustomFormat, 문자열
Windows에서는 다음 기준을 따른다:
-
webCustomFormat에 "Web Custom Format"을 할당한다.
-
webCustomFormat을 반환한다.
MacOS에서는 다음 기준을 따른다:
-
webCustomFormat에 "org.w3.web-custom-format.type-"을 할당한다.
-
webCustomFormat을 반환한다.
Linux, ChromeOS, Android에서는 다음 기준을 따른다:
-
webCustomFormat에 "application/web;type="custom/format"을 할당한다.
-
webCustomFormat을 반환한다.
클립보드 이벤트 발생시키기
- 입력
-
e,
ClipboardEvent발생시킬 이벤트 - 출력
-
없음
-
clear-was-called을 false로 한다.
-
types-to-clear를 빈 리스트로 한다.
-
clipboard-event-data를 새로운
DataTransfer객체로,items리스트는 빈 값으로 생성한다. -
clipboard-entry를 현재 클립보드 콘텐츠의 시퀀스 번호로 하거나, OS 클립보드가 시퀀스 번호를 지원하지 않는 경우 null로 한다.
-
trusted를 이벤트가 사용자 에이전트에 의해 생성된 경우 true, 그렇지 않으면 false로 한다.
-
target을 다음과 같이 설정한다:
-
이벤트를 다음과 같이 처리한다:
-
e가 "paste"이면,
-
clipboard-event-data의 내부 drag data store mode 플래그를 read-only로 설정한다.
-
trusted가 true이거나, 구현체가 스크립트 생성 이벤트에 OS 클립보드 읽기 권한을 부여하도록 설정된 경우,
-
OS 클립보드의 각 clipboard-part에 대해 아래를 수행한다:
-
clipboard-part가 평문 텍스트를 포함하면,
-
텍스트가 스크립트 엔진 내부 인코딩에 맞는지 확인한다.
-
new-data를 새로운
DataTransferItem으로, drag data item kind는 string, drag data item type string은 text/plain으로 한다. -
new-data의 데이터를 평문 텍스트로 설정한다.
-
new-data를 clipboard-event-data의
items리스트에 추가한다.
-
-
clipboard-part가 파일 참조를 나타내면, 각 파일 참조에 대해:
-
참조된 파일의 MIME 타입을 결정한다.
-
new-data를 새로운
DataTransferItem으로, drag data item kind는 file, drag data item type string은 해당 MIME 타입(모르면application/octet-stream)으로 한다. -
new-data의 데이터를 파일 참조 데이터로 설정한다.
-
new-data를 clipboard-event-data의
items리스트에 추가한다.
-
-
clipboard-part가 HTML 또는 XHTML 형식의 텍스트를 포함하면(OS 클립보드 포맷 설명 기준),
-
구현체가 HTML 붙여넣기를 지원하면, HTML 붙여넣기 이벤트 처리(clipboard-part, clipboard-event-data)를 호출한다.
-
-
clipboard-part가 다른 지원되는 바이너리 혹은 텍스트 기반 포맷(see 필수 데이터 타입)의 데이터를 포함하면,
-
데이터의 MIME 타입 결정
-
new-data를 새로운
DataTransferItem으로, drag data item kind는 file, drag data item type string은 해당 MIME 타입으로 한다. -
new-data의 데이터를 바이너리 또는 텍스트 기반 데이터로 설정한다.
-
new-data를 clipboard-event-data의
items리스트에 추가한다.
-
-
-
-
clipboard-event-data의
files속성을 clipboard-event-data의items항목에 맞게 갱신한다. -
clipboard-event-data의
types속성을 clipboard-event-data의items항목에 맞게 갱신한다.
-
-
e가 "copy" 또는 "cut"이면,
-
해당
DataTransfer객체의 내부 drag data store mode 플래그를 read/write로 한다.
-
-
-
e의
clipboardData를 clipboard-event-data로 설정한다. -
e의
isTrusted를 trusted로 설정한다. -
e의
composed를 true로 설정한다. -
이벤트 e를 target에 버블링되고 취소 가능한 이벤트로,
ClipboardEvent인터페이스로 디스패치한다.이벤트 디스패치 중 데이터 접근에 대한 구현 요구사항은 [HTML]에 정의되어 있다. 추가적인 클립보드 이벤트 전용 처리 규칙은 아래와 같다:
왜 여기서 정의하는가? 왜 HTML 명세에 포함되지 않는가?
-
스크립트가 clearData() 또는
clear()를 호출하고,DataTransfer객체 내부 drag data store mode 플래그가 read/write이면,-
clear-was-called 플래그를 true로 설정한다. 인자가 주어지면 해당 인자를 types-to-clear 리스트에 추가한다.
-
-
스크립트가 setData()를 호출하거나 아이템을 수정하고, clear-was-called 플래그가 true이면,
-
types-to-clear 리스트가 비어있으면,
-
clear-was-called 플래그를 false로 한다.
-
-
그 외, setData()의
type인자 또는 새 아이템의 drag data item type string이 types-to-clear 리스트에 있다면,-
리스트에서 해당 항목을 제거하고, 리스트가 비어있으면 clear-was-called 플래그를 false로 한다.
-
-
-
스크립트가 getData()를 호출하거나
DataTransferItemList에 접근하고 clipboard-entry가 설정되어 있으면,-
클립보드 데이터의 시퀀스 번호가 clipboard-entry와 일치하는지 확인한다. 클립보드가 더 이상 동일한 항목을 포함하지 않으면
DataTransferItemList객체의 내부 drag data store mode를 protected로 설정한다.
-
경고! paste 이벤트를 감시하는 악성 스크립트가 사용자가 미래에 클립보드에 넣는 것을 무한 반복 루프를 통해 읽을 수 있습니다. 클립보드 시퀀스 번호를 지원하지 않는 플랫폼에서는 추가 제한이 필요합니다.
-
HTML 붙여넣기 이벤트 처리
- 입력
-
clipboard-part, 처리할 클립보드 파트
clipboard-event-data, 이 이벤트용
DataTransfer객체 - 출력
-
없음
-
new-data를 새로운
DataTransferItem으로, drag data item kind는 Plain Unicode string, drag data item type string은 text/html 또는 application/xhtml+xml로 한다. -
clipboard-part에서 마크업을 추출하고, 관련 파서를 사용해 DOM 트리를 생성한다.
-
마크업의 소스 URL이 알려져 있다면, HREF와 SRC 속성의 상대 URL을 소스 URL을 기준으로 모두 절대 URL로 변환해 해당 속성에 설정한다.
-
마크업의 출처가 로컬 애플리케이션이라면, 로컬 파일이나 OS 클립보드의 다른 부분을 참조하는지 확인한다. 참조가 있다면, 서브파트 참조는 반드시 cid: URL 스킴([RFC2392])을 활용해 content-id 참조로 바꿔야 한다. 이를 위해 아래 단계를 따른다:
이 단계가 필요한가? 내부 참조가 있는 다중 파트 지원 네이티브(플랫폼) 클립보드 구현이 존재하는가?
이 기능은 꼭 필요한지, 그리고 크로스 플랫폼 테스트가 어렵기 때문에 위험에 처해있음.
-
clipboard-event-data의
items에 이미 참조된 파일 또는 클립보드 파트에 대한 항목이 있으면,-
itemNumber를 해당 항목의 인덱스로 설정한다.
-
-
그렇지 않으면,
-
new-file-data를 새
DataTransferItem객체로 하고, drag data item kind는 "file"로, drag data item type string은 파일 또는 클립보드 파트의 MIME 타입(알 수 없다면application/octet-stream)으로 설정한다. -
file-info를 새
File객체로 하며,name은 HTML 속성 값의 이름 부분으로,lastModified는 참조된 파일의 타임스탬프 또는 클립보드 파트라면 0으로 설정한다. -
new-file-data의 내부
File객체를 file-info로 설정한다. -
new-file-data를 clipboard-event-data의
items에 추가하고, itemNumber를DataTransferItemList에서 해당 항목의 인덱스로 한다.
-
-
로컬 파일 또는 클립보드 파트를 참조하는 DOM 속성을 'cid:'와 itemNumber로 갱신한다.
-
-
처리된 DOM을 직렬화하여 new-data에 생성된 HTML 코드로 갱신한다.
-
new-data를 clipboard-event-data의
items에 추가한다.