# U.chat()과 room 객체

> 페이지 스크립트의 진입점 U.chat()과 이벤트 콜백이 받는 room 객체의 값·함수 목록이에요.

페이지 스크립트는 `U.chat()`으로 채팅방을 고르고, 이벤트 콜백의 첫 인자로 `room` 객체를 받아요. 이 문서는 둘의 정본 목록이에요. 이벤트 이름과 `data`는 [이벤트](/doc/3.3), 채널(`room.plugin`)은 [채널 API와 한도](/doc/3.5), 스킨 UI(`room.skin`)는 [스킨 UI API](/doc/3.4)를 보세요.

## U.chat() {#u-chat}

| 호출 | 반환 |
| --- | --- |
| `U.chat('my-room')` — 아직 설치되지 않은 방 | 등록기 `{ on, off }` |
| `U.chat('my-room')` — 설치된 방 | 그 방의 `room` 객체(`on`, `off` 포함) |
| `U.chat('*')` | 모든 방에 거는 등록기 `{ on, off }` |

어느 쪽이든 `.on(이름, 콜백)`으로 이벤트를 걸 수 있어요.

```js
U.chat('my-room').on('after.join', function (room, data) {
	room.print(data.my.nick + '님, 환영합니다.');
});
```

- `U`는 uchat.js가 만들어요. uchat.js는 `async`로 읽히므로 그 전에 부를 코드는 미리 등록 코드가 필요해요. [비동기 로딩과 여러 채팅방](/doc/2.2)을 보세요.
- 입장 확인(봇 검사) 화면이 떠 있는 동안에는 `U.chat('my-room')`이 `undefined`를 돌려줄 수 있어요. 페이지 로드 직후에 거는 코드는 미리 등록 코드 안에 두세요.

## on / off {#on-off}

| 함수 | 인자 | 설명 |
| --- | --- | --- |
| `on(name, fn)` | 이벤트 이름(`이름#이름표` 가능), `fn(room, data)` | 콜백 등록. `after.create`는 이미 준비된 방이면 즉시 한 번 불러요 |
| `off(name)` | `'이름'`, `'#이름표'`, `'이름#이름표'` | 맞는 등록을 지워요 |

| `off` 인자 | 지우는 것 |
| --- | --- |
| `'after.message'` | 그 이벤트의 모든 등록(이름표 유무와 관계없이) |
| `'#stats'` | 이름표가 `stats`인 모든 등록 |
| `'after.message#stats'` | 정확히 그 이름으로 등록한 것만 |

- `U.chat('*').off(...)`는 `U.chat('my-room')`이나 `room.on`으로 방별로 건 등록까지 지워요. 다른 스크립트의 등록을 지우지 않도록 고유한 이름표를 쓰세요.
- `U.chat('my-room').off(...)`와 `room.off(...)`는 그 방에 건 등록만 지워요. `'*'` 등록은 남아요.
- `off()`는 인자 없이 부르지 마세요. 지울 등록이 있으면 오류가 나요.
- 같은 이벤트의 콜백은 등록한 순서대로 불려요. 콜백 안의 예외는 콘솔에 기록되고 다음 콜백은 계속 불려요.

## room 값 {#properties}

| 이름 | 형식 | 설명 |
| --- | --- | --- |
| `room.id` | 문자열 | 채팅방 아이디 |
| `room.my` | [사용자 객체](#user-object) | 내 정보. 입장(`after.join`) 전에는 빈 객체 |
| `room.info` | 객체 | 채팅방 정보. 입장 전에는 빈 객체. 아래 [room.info](#room-info) |
| `room.user` | `{ list, get }` | 접속자. 아래 [room.user](#room-user) |
| `room.setting` | `{ get, set, save, data }` | 이 브라우저에 저장되는 사용자 설정. 아래 [room.setting](#room-setting) |
| `room.plugin` | 객체 | 채널. [채널 API와 한도](/doc/3.5) |
| `room.action` | 객체 | 보내기·명령. 아래 [room.action](#room-action) |
| `room.skin` | 객체 | 스킨 UI API. [스킨 UI API](/doc/3.4) |
| `room.skin.arguments` | 객체 | 관리 페이지 스킨 설정에 `skin_arguments` 속성을 합친 값 |
| `room.agent` | `{ userAgent, charset, mobile, android, ios, webkit }` | 브라우저 정보. `userAgent`는 소문자, `webkit`은 버전 숫자 또는 `false` |
| `room.language` | `{ system, error }` | 현재 언어의 안내·오류 문구. 오류 문구는 `room.language.error[코드]` |
| `room.locale` | 문자열 | 정해진 화면 언어 코드(`ko`, `en`, `ja`). 언어팩을 받기 전에는 빈 문자열 |

## 사용자 객체 {#user-object}

`room.my`, `room.user.get()`, 이벤트의 `data.user` 등이 같은 모양이에요.

| 키 | 형식 | 설명 |
| --- | --- | --- |
| `nick` | 문자열 | 닉네임 |
| `id` | 문자열 | 회원 아이디(회원 연동). 없으면 빈 값 |
| `level` | 숫자/문자열 | 레벨(회원 연동) |
| `auth` | 숫자 | `0` 손님, `1` 회원, `2` 부관리자, `3` 관리자, `4` 서버(REST API 발신·채널 저장값. 이때 `nick` 등은 비어 있음) |
| `icons` | 문자열 | 아이콘 주소 목록(회원 연동의 `icons` 값) |
| `nickcon` | 문자열 | 닉네임 대신 보일 이미지 주소 |
| `connected` | 문자열 | 입장 시각 `'YYYY-MM-DD HH:MM:SS'`(보는 사람의 시간대) |
| `time` | 숫자 | 입장 시각(Unix 초) |
| `mute` | `0`/`1` | 채팅금지 중이면 `1` |
| `session` | 문자열 | 세션 식별값(16진수). 무시하기·권한 부여의 기준 |
| `profileimg` | 문자열 | 프로필 이미지 주소(있을 때만) |

## room.info {#room-info}

| 키 | 설명 |
| --- | --- |
| `id`, `name` | 채팅방 아이디, 이름 |
| `mode` | `0` 일반, `1` 개인채널, `4` 채널 채팅방 |
| `created` | 개설 시각 `'YYYY-MM-DD HH:MM:SS'` |
| `frozen` | 입장할 때 얼린 상태였으면 `1`. 얼리기·풀기를 해도 바뀌지 않으므로 `system` 이벤트(`frozen`, `unfrozen`)로 확인해요 |
| `whisper`, `call`, `individual`, `font` | 귓속말·호출·개인채널·글꼴 꾸미기 사용 여부(`0`/`1`) |
| `userLinkage` | 회원 연동을 켰으면 `1` |
| `slowSeconds` | 슬로우 모드 간격(초). 꺼져 있으면 `0` |

채팅방 설정이 바뀌면 바뀐 키만 `room.info`에 합쳐지고 `update` 이벤트가 와요.

## room.user {#room-user}

| 이름 | 설명 |
| --- | --- |
| `room.user.get(nick)` | 닉네임으로 사용자 객체를 찾아요. 없으면 `undefined` |
| `room.user.list` | 지금 접속자 목록. 배열이 아니라 객체이며, 키는 `escape(닉네임)`이에요 |

```js
var user = room.user.get('홍길동');
if (user && user.auth >= 2) room.print('관리자입니다.');
```

- 닉네임으로 찾을 때는 `user.get`을 쓰세요. `user.list`의 키는 `escape()`로 인코딩되어 있어 한글 닉네임을 그대로 넣으면 찾지 못해요.
- `user.get`은 메시지로 본 사람처럼 지금 접속 중이 아닌 사용자도 돌려줄 수 있어요. 접속 여부는 `user.list`로 확인해요.
- `user.list`는 입장·퇴장 알림(`user.join`, `user.quit`)을 받을 때만 바뀌어요. 기본 스킨에서 사용자 목록이 열려 있거나 접속자가 100명 이상인 방은 이 알림이 오지 않으므로 `user.list`가 입장 때 모습에서 멈춰 있을 수 있어요. → [이벤트](/doc/3.3#users)

## room 함수 {#functions}

| 함수 | 반환 | 설명 |
| --- | --- | --- |
| `room.print(html)` | — | 내 화면에만 안내 줄을 HTML로 띄워요. 스크립트를 실행할 수 있는 요소만 지워지므로 사용자 입력을 넣을 때는 직접 이스케이프하세요. `system` 이벤트(`type: 'notice'`)도 발생해요 |
| `room.on(name, fn)` | `room` | 이 방에만 이벤트 등록. [on / off](#on-off)와 같아요 |
| `room.off(name)` | — | 이 방의 등록 해제 |
| `room.now()` | 숫자 | 서버 시계 기준 현재 시각(밀리초, 초 단위로 맞춰짐) |
| `room.getTimeStamp([sec])` | 문자열 | Unix 초를 `'YYYY-MM-DD HH:MM:SS'`(보는 사람의 시간대)로. 생략하면 현재 서버 시각 |
| `room.reload()` | — | 채팅방을 지우고 같은 자리에 다시 설치해요. 이 방에 건 이벤트(`U.chat('my-room')`, `room.on`)도 지워지므로 다시 걸어야 해요. `'*'` 등록은 남아요 |
| `room.disconnect()` | — | 연결을 끊어요. 네트워크 오류로 끊긴 것처럼 처리되어 자동으로 다시 접속해요 |

## room.action {#room-action}

| 함수 | 반환 | 설명 |
| --- | --- | --- |
| `send(message, style)` | `true`/`false` | 메시지를 보내요. `style`은 `{ bold, italic, underline, color }`(모두 선택) |
| `slowRemaining()` | 밀리초 | 슬로우 모드로 다음 전송까지 남은 시간. 기다릴 필요가 없으면 `0` |
| `command(type, ...args)` | `before.command`에서 취소하면 `false`, 그 밖에는 없음 | 명령을 실행해요. 아래 [명령](#commands) |
| `plugin(type, args)` | `true`/`false` | 채팅창에 `!type 인자`를 입력한 것과 같이 그 채널의 `addParser` 콜백을 불러요. 자세한 동작은 [채널 API와 한도](/doc/3.5#parser) |

```js
room.action.send('안녕하세요');
room.action.send('중요!', { bold: true, color: '#e11d48' });
```

- `send`는 연결되지 않았거나, 내용이 비었거나, 슬로우 모드로 기다려야 하거나, `before.send`에서 막히면 `false`를 돌려줘요. `true`는 서버로 보냈다는 뜻이며, 서버가 거절하면 `error` 이벤트가 와요.
- `color`는 `#rgb`, `#rrggbb`, `rgb(r, g, b)`, 색 이름을 받아요.
- 관리자·부관리자가 아니면 보낸 뒤 슬로우 모드 대기가 시작돼요.

## 명령 {#commands}

`room.action.command(type, ...args)`의 `type`은 대소문자와 `_`를 무시해요(`un_ignore` → `unignore`). 연결 전에는 아무 일도 하지 않아요. 권한이 없거나 인자가 틀리면 `error` 이벤트가 와요.

자주 쓰는 명령:

| 명령 | 인자 | 권한 | 설명 |
| --- | --- | --- | --- |
| `whisper` | 닉네임, 내용 | — | 귓속말 |
| `call` | 닉네임 | — | 호출 |
| `ignore`, `unignore` | 닉네임 | — | 무시하기·해제(이 브라우저에 저장) |
| `report` | 닉네임, 사유 | — | 신고 |
| `changeinfo` | `{ nick: '새 닉네임' }` | — | 닉네임 바꾸기 |
| `password` | 비밀번호 | — | 접속 비밀번호를 넣고 다시 입장 |
| `chatlist` | 개수(기본 15, 최대 25) | — | 지난 대화와 나와 관련된 귓속말·호출·초대를 다시 받기 |
| `noticelist` | — | — | 채팅방 공지를 다시 받기(`system` 이벤트 `notice`로 옴) |
| `individual` | — | — | 내 개인채널을 새 창으로 열기 |
| `invite` | 닉네임 | — | 그 사람을 내 개인채널에 초대. 개인채널 창이 없으면 먼저 열어요 |
| `popup` | — | — | 이 채팅방을 새 창(400×600)으로 열기 |
| `io` | `true`/`false` | — | 입장·퇴장 알림 받기 켜기·끄기. 끄면 접속자 수(`user.count`)만 받아요 |
| `login` | 관리자 비밀번호 | — | 관리자 되기. 회원 연동 방에서는 쓸 수 없어요 |
| `info` | 닉네임 | 부관리자(자기 자신은 누구나) | 사용자 정보 |
| `notice` | 내용 | 부관리자 | 공지 |
| `mute` | 닉네임, 분, 사유 | 부관리자 | 채팅금지. 최대 30일(43200분) |
| `unmute` | 닉네임 | 부관리자 | 채팅금지 해제 |
| `ban` | 닉네임, 사유, 기간(초) | 부관리자 | 차단. 기간을 비우거나 0이면 영구 |
| `ip` | 닉네임 | 부관리자 | IP 확인 |
| `freeze`, `unfreeze` | — | 부관리자 | 채팅방 얼리기·풀기 |
| `clearlog` | — | 부관리자 | 대화 청소(권한이 없으면 내 화면만) |
| `op`, `deop` | 닉네임 | 관리자 | 부관리자 지정·해제 |
| `logout` | — | 관리자 | 관리자 권한 내려놓기 |
| `adminpage` | — | 관리자 | 관리 페이지를 새 창으로 열기 |
| `upload` | 콜백 | — | 레거시 스킨 전용. 업로드 창을 열고 결과를 `콜백(json)`으로 받아요 |

```js
room.action.command('whisper', '홍길동', '잠깐 이야기할 수 있을까요?');
room.action.command('changeinfo', { nick: '새닉네임' });
```

권한 검사는 서버가 다시 해요. 화면에서 버튼을 숨기는 것만으로 권한을 막을 수는 없고, 반대로 권한이 없는 명령은 보내도 거절돼요.

## room.setting {#room-setting}

이 브라우저에만 저장되는 사용자 설정이에요(localStorage). 기본 스킨의 설정과 같은 저장소를 쓰므로 직접 만든 키에는 접두어를 붙이세요.

| 함수 | 설명 |
| --- | --- |
| `room.setting.get(key)` | 값 읽기 |
| `room.setting.set(key, value)` | 값을 쓰고 바로 저장 |
| `room.setting.save()` | 현재 값을 저장 |
| `room.setting.data` | 설정 객체 자체 |

```js
room.setting.set('myScript.muted', true);
room.setting.get('myScript.muted'); // true
```

저장소를 쓸 수 없는 브라우저(사생활 보호 모드 등)에서는 새로고침하면 값이 사라질 수 있어요.
