조기 게시로 인한 어색한 실수

나는 분명히 다양한 커뮤니케이션 앱(채팅 중심이 아닌 앱)에서 이른바 ‘조기 게시’ 증상을 겪고 있는 것 같다.

주요하게는 이메일(Gmail)과 Discourse다.

상황은 이렇다. 메시지를 작성하다가 실수로 전송하게 된다. 내 취향으로서는 너무 자주 일어나는 불편한 일이다. 아마도 Ctrl + Enter 같은 키보드 단축키, 혹은 (아마 더 흔하게?) Tab ↹를 누른 뒤 Enter를 누르는 습관 때문일 것이다.

Gmail에서는 이 문제를 관리할 수 있다: 이메일 전송을 취소할 수 있는 짧은 시간 창이 있다. 좋다! :raising_hands:
작성 중 게시물을 실수로 전송하는 것을 완전히 피하기 위해, 수신자 입력란을 비워둔다. 이메일을 보내기 직전에야 수신자를 입력한다.

하지만 Discourse에서는 PM(개인 메시지)이 아닌 경우 이것이 불가능하다. 카테고리 선택기에서 기본 카테고리를 제거해 보았다. 그러면 게시물을 전송할 때 "카테고리는 비워둘 수 없습니다"라는 메시지가 표시될 것이라 생각했지만, 아쉽게도 그렇게 되지 않았다.

주제나 답변을 너무 일찍 제출하는 것은 부끄러운 일이다. 바로 삭제할 수는 있지만, 다른 사용자에게 내용은 여전히 표시된다(그들은 단지 편집 아이콘을 클릭하면 된다). 이는 Discourse의 기본 동작이기 때문이다. 그리고 게시물이 삭제된 상태에서는 내용을 완성할 수 없으므로, 나중에 삭제를 되돌릴 수도 없다.

결국, 내 게시물을 완성하지 않은 상태로 두어야 한다(보통 문장이나 단어의 중간에서 :woozy_face:). 그리고 인내심을 갖고 편집해야 하는데, 나는 글쓰기 속도도 느려서 이것이 마음에 들지 않는다. 아니면 게시물을 삭제하고 새로운 주제/게시물을 다시 작성해야 한다.

이것은 주로 긴 메시지나 많은 고민이 필요한 게시물에서 자주 발생하기 때문에, 메시지 전송을 완전히 방지하는 토글 가능한 잠금 :locked_with_pen: 아이콘이 있으면 좋겠다.

나는 이것이 Discourse 기능에 대한 특정 제안을 하는 것은 아니다… 많은 사용자가 이 문제를 겪는다면 모를까 :smile:

이것은 더 이 경험과, Discourse에서 조기 전송으로 인한 부끄러움에 대해 공유하고, 다른 회원들의 의견을 듣고, 이를 방지하기 위한 아이디어를 나누는 것에 더 가깝다.

나에게는 사용자 스크립트만으로도 충분할 것이다. 불행히도, 나는 Discourse의 키보드 단축키로 게시물을 전송하는 것을 방지하는 방법을 모르고, AI도 모른다.
수정: The awkward mishap of premature posting - #10 by Canapin 참고

조기 게시에 영향을 받고 계신가요?

  • 아니오
0 voters

Discourse에서 컴포저를 "잠금"할 수 있는 기능을 원하나요?

  • 네 (내장 기능)
  • 네 (제3자 기능)
  • 아니오 — 나는 모험적으로 살고 싶다
0 voters

여러분의 생각을 듣고 싶다!

6개의 좋아요

저도 그래요 — 터치스크린을 사용할 때요. 정말 짜증나네요.

2개의 좋아요

정말 공감 가는 내용입니다. 저도 디스코URS의 채팅(즉, 디스코URS의 채팅)에서 같은 일이 생깁니다. 가끔은 영구 삭제 전에 확인 팝업이나 10초 정도의 확인 시간을 원할 때가 있습니다.

4개의 좋아요

나는 데스크톱을 99% 사용해서 조기 게시가 실제로는 잘 안 일어나지만, 그 어색함은 이해할 수 있습니다. 사용자가 추가 편집을 위해 게시물을 잠시 숨길 수 있는 짧은 시간대를 제공하는 것이 의미가 있을까요 — 아마도 아직 답글이 없는 경우에만?

수정: 물론 그렇게 해도 편집 이력은 숨겨지지 않겠지만… :sweat_smile:

2개의 좋아요

존중은 하지만, 체감되지는 않아요. 저는 편집 유예 기간을 훨씬 선호합니다. 마음껏 다시 읽고 교정할 수 있고, 중요한 긴 글을 올린 후에도 여전히 오탈자를 발견하거든요. 편집 기능이 제 실수를 잘 감춰줍니다.

사람마다 실수하는 방식도 다르니까요.

1개의 좋아요

나는 긴 웹사이트 필드를 채울 때 외부 편집기를 사용합니다. 물론 디스코러스 포스트도 포함됩니다. 편집기에서는 평소 사용하는 프로그래머용 키 바인딩을 모두 사용할 수 있으므로 거의 모든 면에서 더 좋습니다. 텍스트가 완성되었는지 만족스러울 때에만 복사-붙여넣기를 사용해 작성기에 전달한 뒤, 큰 버튼을 누릅니다.

이 워크플로우를 고려해 보신 적 있나요?

2개의 좋아요

다양한 경험을 접할 수 있어 흥미롭네요. 저는 실수로 스마트폰으로 게시글을 올린 적이 없고, 데스크톱에서만 작성합니다.

네, 다른 맥락에서는 사용하고 있습니다. 저는 타겟 메신저 앱에 붙여넣기하기 전에 먼저 Google Docs에 메시지를 작성합니다.

하지만 Discourse에서는 게시글에 사진을 추가하거나, 인용을 사용하거나, Discourse 고유 기능을 사용할 때 조금 번거로워요.


수일째 초안을 작성하고 있는데, 작업을 할 때마다 조금씩 스트레스가 됩니다. 실수로 보내버리지 않도록 항상 ekstra 조심해야 하거든요. :lolsob:

1개의 좋아요

긴 글을 쓸 때 저는 비슷한 방법을 사용합니다. 하지만 Google 같은 서비스 사용을 줄이려고 하고, 주로 iPad에서 작업하기 때문에 제 도구는 Ulysses 앱입니다. 대부분 마크다운을 지원해서 그렇습니다. 다만 Discourse가 사용하는 문법과는 완전히 같지는 않습니다.

이 점에 대해 좀 복잡한 감정이 있습니다. 한편으로는 앱을 분리해서 써야 하는 게 싫습니다(WordPress에서도 이렇게 하는데, 요즘 거기서 콘텐츠를 만드는 건 고통스럽습니다). 하지만 동시에 더 견고하고 중앙 집중식인 환경을 갖게 됩니다.

이게 저한테 큰 문제일까요? 아니요, 그냥 짜증나는 수준입니다. Discourse가 미완성 작업을 남겨두는 방식을 바꿨을 때가 더 재앙이었죠. 근육 기억 때문에 너무 많은 초안을 잃어버렸거든요 :zany_face:

1개의 좋아요

해결책으로, 초안 역할을 하도록 본인에게 개인 메시지를 작성해 두는 것입니다. 실수로 보내도 자신에게만 보이므로 아무런 해가 되지 않습니다. :slight_smile:

2개의 좋아요

여기에는 작성기에 토글 가능한 잠금 기능을 추가하는 userscript가 있습니다.
키보드 단축키도 비활성화하며, 모바일에서도 작동합니다.

IXlc8u1sm4

https://greasyfork.org/en/scripts/566254-discourse-composer-safety-lock

사용하는 포럼에서 활성화하려면 @match 줄을 추가하거나 제거하세요.

// ==UserScript==
// @name         Discourse Composer Safety Lock
// @namespace    https://meta.discourse.org
// @version      2.0
// @description  작성기에 실수로 게시물이 제출되는 것을 방지하기 위한 토글 가능한 자물쇠
// @author       Canapin & AI
// @match        https://meta.discourse.org/*
// @grant        none
// @license MIT
// ==/UserScript==
(function () {
  "use strict";
 
  let locked = false;
 
  // #reply-control에 캡처 단계 리스너를 추가하여 Ctrl/Cmd/Alt+Enter를 차단
  function attachBlocker(replyControl) {
    if (replyControl._safetyLockAttached) return;
    replyControl._safetyLockAttached = true;
 
    replyControl.addEventListener(
      "keydown",
      function (e) {
        if (!locked) return;
        if (e.key === "Enter" && (e.ctrlKey || e.metaKey || e.altKey)) {
          e.stopImmediatePropagation();
          e.stopPropagation();
          e.preventDefault();
        }
      },
      true
    );
  }
 
  function updateButtons() {
    const rc = document.getElementById("reply-control");
    if (!rc) return;
    rc.querySelectorAll(".save-or-cancel .btn-primary").forEach((btn) => {
      if (locked) {
        btn.style.pointerEvents = "none";
        btn.style.filter = "grayscale(1) opacity(0.4)";
        btn.setAttribute("tabindex", "-1");
      } else {
        btn.style.pointerEvents = "";
        btn.style.filter = "";
        btn.removeAttribute("tabindex");
      }
    });
  }
 
  // 저장 버튼에 대한 캡처 단계 클릭 차단기
  document.addEventListener(
    "click",
    function (e) {
      if (!locked) return;
      if (e.target.closest(".save-or-cancel .btn-primary")) {
        e.stopImmediatePropagation();
        e.stopPropagation();
        e.preventDefault();
      }
    },
    true
  );
 
  // 포커스된 저장 버튼에서 Enter 키에 대한 캡처 단계 keydown 차단기
  document.addEventListener(
    "keydown",
    function (e) {
      if (!locked) return;
      if (
        e.key === "Enter" &&
        e.target.closest(".save-or-cancel .btn-primary")
      ) {
        e.stopImmediatePropagation();
        e.stopPropagation();
        e.preventDefault();
      }
    },
    true
  );
 
  function injectPadlock() {
    if (document.getElementById("composer-lock-btn")) return;
    const title = document.querySelector(".composer-action-title");
    if (!title) return;
 
    const btn = document.createElement("span");
    btn.id = "composer-lock-btn";
    btn.textContent = locked ? "\u{1F512}" : "\u{1F513}";
    btn.style.cssText =
      "cursor:pointer;margin-left:10px;font-size:1.1em;user-select:none;opacity:" +
      (locked ? "1" : "0.5");
 
    btn.addEventListener("click", (e) => {
      e.preventDefault();
      e.stopPropagation();
      locked = !locked;
      btn.textContent = locked ? "\u{1F512}" : "\u{1F513}";
      btn.style.opacity = locked ? "1" : "0.5";
      updateButtons();
    });
 
    title.appendChild(btn);
    updateButtons();
  }
 
  const observer = new MutationObserver(() => {
    const rc = document.getElementById("reply-control");
    if (rc && rc.classList.contains("open")) {
      attachBlocker(rc);
      injectPadlock();
      updateButtons();
    }
  });
 
  observer.observe(document.body, {
    childList: true,
    subtree: true,
    attributes: true,
    attributeFilter: ["class"],
  });
 
  const rc = document.getElementById("reply-control");
  if (rc && rc.classList.contains("open")) {
    attachBlocker(rc);
    injectPadlock();
    updateButtons();
  }
})();
6개의 좋아요

보통 이런 문제는 겪지 않아요. 왜 그런지 잘 모르겠네요. 다만, 실수로 이메일을 잘못 보낸 적은 있어요. 사실 더 자주 일어나는 일은, 이메일을 보낸 직후에 (받는 사람이 잘못됐나? 정보가 빠졌나?) 하는 의문이 드는 건데, 그걸 Gmail이 몇 초 동안 제공해주는 « 보내기 취소 » 링크로 해소할 수 있어서 정말 좋아요. 그래도 그런 경우는 자주 있지는 않아요.

그래서, 게시물을 올릴 때도 비슷한 기능이 있으면 좋겠다는 생각이 들었어요. 게시물을 올린 후 몇 초 동안 « 아, 이건 그렇게 올라가면 안 되는 거였는데 » 버튼이 있으면 좋겠어요.

시프트+엔터, 컨트롤+엔터 단축키를 자주 사용하기 때문에 이런 일이 많이 일어납니다.

큰 문제는 아니니 그냥 게시글을 수정하면 됩니다.

민감한 내용은 별도의 편집기에서 먼저 작성한 후, 전송하기 전에 해당 애플리케이션에 붙여넣습니다.

메타에 올린 사용자 스크립트를 사용했는데, 글을 쓸 때 정말 마음이 편해져요!

이제 (예전보다 더) 이런 기능이 내장되어 있으면 좋겠다는 생각이 듭니다 :face_with_tongue:

하지만 디자이너가 이미 말을 한 것 같네요!

image

:laughing:

2개의 좋아요

이 작업을 수행하는 간단한 TC를 만들었습니다. 작성기에는 잠금/잠금 해제 버튼이 있습니다.

곧 Meta 토픽을 게시할 예정입니다.

수정: 여기 있습니다: Lock Composer

1개의 좋아요

보통은 주제(토픽)를 생성한 후 마지막에 제목을 추가합니다. 이렇게 하면 주제가 게시되는 것을 방지할 수 있기 때문이죠 (다만, 댓글에는 적용되지 않습니다).

화면 키보드가 작성 창을 위로 밀어 올리는 태블릿에서는 실수로 게시물을 게시하기가 매우 쉽습니다.

3개의 좋아요