Chromium에 사용자 인터페이스(UI)를 추가한 구글 크롬 클론 코딩 프로젝트
-
메인 프로세스에서 싱글톤 패턴으로 전역 상태 관리
- 앱 실행 시점에 초기화되는 데이터
-
windows : 모든 Window 인스턴스. 각 윈도우에는 현재 실행 중인 BrowserWindow 인스턴스와 tabs 정보 등이 함께 관리됨.
- id : browserWindow.id를 uid로 사용. 프로세스 간 통신을 위해 일치시키는 것이 용이함.
- tabs : 특정 윈도우의 모든 Tab 인스턴스. 하나의 Tab 인스턴스에는 하나의 BrowserView 인스턴스와 tabId 정보가 함께 관리됨.
-
tabId : 하나의 탭이 생성될 때마다 1씩 증가. 각 탭의 uid로 배정되는 숫자 데이터.
-
로컬 머신에 JSON 파일로 저장하고 읽는 데이터 (custom-database.json)
-
즐겨찾기 데이터는 favorites key에 배열로 저장
- 개별 즐겨찾기 데이터 구조: ({ title, url, favicon })
-
특정 윈도우의 헤더 프로세스에서 메인 프로세스에 해당 윈도우 제거, 최소화, 최대화 토글 요청
-
특정 윈도우의 헤더 프로세스에서 메인 프로세스에 tabs 정보를 요청하고, 데이터를 응답받아 화면의 html 태그 추가 및 내용 수정
-
특정 윈도우의 뷰 프로세스에서 메인 프로세스에 개발자 도구 열기, 탭 제거 등의 요청하고, 메인 프로세스는 헤더 프로세스 혹은 해당 뷰 프로세스로 응답
-
앱 실행시, 맥에서 아이콘 클릭시 새 윈도우 생성
-
창이 생성되면 생성된 창에 focus되도록 명시
- 앱 실행시, 생성된 창에 focus시키고, 새 탭인 경우 omnibox에 초점이 오도록 설정
-
창에 focus가 들어온 경우 창(browser window)으로 간 focus를 헤더(browser view)로 그대로 이동시키기 (개발자 입장에서는 포함 관계지만, 실질적으로 서로 별개의 프로세스)
-
새 탭인 경우 화면의 어디를 클릭했던지와 무관하게, 무조건 omnibox로 초점이 오도록 설정
-
새 탭이 아니라면 마지막으로 있던 위치에 초점 가도록 내버려두기
-
focus 탭 정보 업데이트 : 다른 창에서의 작업으로 즐겨찾기 정보가 변했을 수 있기 때문에 필요.
-
-
blur된(focus를 잃은) 윈도우는 deactivate시키기 (창이 1개일 때도 포함)
-
헤더의 상단 부분의 배경색 회색으로
-
모든 헤더의 버튼들 회색으로(traffic lights & view utils)
-
focus 다시 얻으면 원상복구
-
-
페이지 뷰 내에서 새 창을 여는 경우 (링크를 shift + 클릭, target="_blank" 속성의 anchor 클릭 등), 디폴트 윈도우가 아닌 커스텀 윈도우를 생성하고 렌더링하도록
- 디버깅: 순환참조 문제 때문에 app에 등록. 페이지 뷰만이 아니라 모든 web contents에 설정됨. (리소스 낭비)
-
마우스로 텍스트 부분만 따로 선택할 수 없도록 설정
-
헤더 내 스크롤 생성 방지
-
더블클릭시 toggle maximize
- event delegation으로 다른 버튼들 더블클릭된 경우에는 동작하지 않도록 명시
-
윈도우든 맥이든 맥의 traffic lights 기능 그대로 구현
- 화면 닫기
- 화면 최소화
- 전체화면 모드 토글
-
특정 버튼을 누르고 있으면 해당 버튼만 살짝 어둡게 색상 변경
-
특정 버튼 누른 상태로 마우스 이동시, 드래그되지 않도록 설정
-
특정 버튼에 마우스 hover시 클릭했을 때 발생할 이벤트에 대한 설명 표시
-
focus되지 않은 윈도우에서는 세 버튼 모두 회색으로 설정
-
hover했을 때 관련 아이콘 보여주기 (보류)
-
title 속성으로 클릭하면 발생할 이벤트 설명 보여주기
-
현재 윈도우에 존재하는 모든 view들에 대한 간략한 정보 표시
- favicon
- 디폴트 favicon
- title 태그
-
특정 탭에 마우스 hover시 탭에 대한 정보 출력
- title 태그
- url 정보
-
새 탭 생성 기능 구현
- 새 탭 생성 시점에 뷰 프로세스 갈아끼우기
- 새 탭 생성 시점에 input에 키보드 자동 focus
- 새 탭(=현재 화면에 보여지는 탭)은 다르게 보이도록 (focus)
- 새 탭 생성시, 메인 프로세스로부터 응답받을 때까지 로딩 상태. 탭 영역 클릭 방지.
-
기존 탭 삭제 기능 구현
- 현재 focus된 탭을 닫는 경우 옆의 탭으로 focus 이동 + 페이지도 이동
-
탭 클릭을 통해 화면에 보여주는 탭 변경
- 현재 화면에 대응되는 탭은 다르게 보이도록 (focus)
-
드래그 앤 드롭 기능 구현
- 탭들 사이에서 좌우 이동시, 탭들의 순서 변경
- 탭들의 영역을 벗어나는 경우 새로운 윈도우 생성
-
반응형 디자인 구현
- 탭의 최소 width는 창 닫는 버튼 크기
- focus된 탭은 창 닫는 x 버튼을 위로
- z-index: focus되지 않은 탭은 favicon + title을 위로
- 탭의 개수가 너무 많으면 새 탭 생성 버튼이 위로 오도록
-
input에 focus된 상태에서는 border를 파란색으로
-
input에 url 입력하여 해당 탭에 페이지 로드
-
url 대신 키워드 입력하는 경우 구글 검색으로 이동
-
로드된 페이지의 title로 해당 탭 업데이트
-
엔터 누르면 곧바로 omnibox에서 unfocus되어 동일한 url 반복 입력 방지 - blur()
-
현재 view에 표시되는 주소가 변한 경우 omnibox에 해당 url 출력
- url 입력에 따른 변화
- 페이지 내 이동에 따른 변화
-
omnibox에 자체적으로 입력만 하고 전송하지 않은 데이터도 그대로 저장 (보류)
-
https:// 부분은 보이지 않도록 설정
-
뒤로 버튼 구현
- 뒤로 못 가는 경우 버튼 클릭 방지 및 어둡게
-
앞으로 버튼 구현
- 앞으로 못 가는 경우 버튼 클릭 방지 및 어둡게
-
뒤로/앞으로 가는 경우 탭의 정보와 뒤로/앞으로 갈 수 있는지의 여부 업데이트
-
새로고침/중지 버튼 구현
- 로딩 중일 때는 중지 버튼으로 임시 변화
- 로딩 종료 후 새로고침 버튼으로 다시 변화
-
title 속성으로 클릭하면 발생할 이벤트 설명 보여주기
-
해당 데스크탑 내부에 자체적으로 즐겨찾기 목록 저장
- 폴더 형식으로 즐겨찾기 목록 구조화
-
omnibox 내에 별 모양 아이콘을 통해 즐겨찾기 여부 확인 가능
-
각 url에 대해 별 모양 토글하여 즐겨찾기 추가 및 제거
- title 속성으로 클릭하면 발생할 이벤트 설명 보여주기
-
새 창 생성 시점에 생성되는 탭에 url이 없는 경우에 보이는 디폴트 화면
-
새 탭 생성 시점에 url이 없는 경우에만 보이는 디폴트 화면
-
새 탭의 화면 내부에서 즐겨찾기 목록 보이도록
-
즐겨찾기 favicon을 로드 실패하는 경우, 새 탭, 연결 실패한 경우의 아이콘인 경우 무조건 디폴트 아이콘을 보여주도록
-
각 즐겨찾기 항목 클릭시, 현재 탭은 해당 url로 이동
-
-
title 속성으로 클릭하면 발생할 이벤트 설명 보여주기
-
새 탭의 화면 내부에서 즐겨찾기 목록 수정 기능
- 즐겨찾기 title 수정
- 즐겨찾기 제거
- 드래그 앤 드롭으로 즐겨찾기 목록 순서 수정
-
입력된 url로 페이지 로드 실패시, 실패 화면으로 이동
- 실패화면에 omnibox에 입력한 url 정보와 에러 코드 출력
- URI 디코딩을 통해 한국어 검색어 등 대응
- 실패화면의 title에는 omnibox에 입력했던 검색어 그대로 출력
- URI 디코딩을 통해 한국어 검색어 등 대응
- favicon은 별도로 생성
- 실패화면에 omnibox에 입력한 url 정보와 에러 코드 출력
-
화면 내에서 우클릭시 기본 도구
- 새 탭 열기
- 새 창 열기
- 개발자 도구 열기 기능
- 새로고침
- 뒤로
- 앞으로
-
a 태그 우클릭시 링크 관련 도구
- 새 탭에서 열기 기능
- 새 창에서 열기 기능
- 링크 주소 복사 기능
-
최종적으로 Menu으로 마이그레이션
-
개발자 도구 토글 : 현재 focus된 창에서 열린 탭의 View에 개발자 도구를 열고 닫기
-
맥 : COMMAND+OPTION+I
-
윈도우 : Ctrl+Shift+I
-
공통 : F12
-
header : 개발자 도구 열릴 수 없도록 방지
-
새 탭과 연결 실패 화면도 그냥 개발자 도구 열 수 있도록 설정. 굳이 막을 이유도 없고, 뒤로/앞으로 가는 경우 열려있던 개발자도구를 닫는 등 별도의 작업이 필요함.
-
-
탭 닫기 : focus된 창의 focus된 탭을 닫고 다른 탭으로 focus를 이동시키는 단축키
- 맥 : COMMAND+W
- 윈도우 : CTRL+W
- 마지막 탭이면 현재 창 닫고 다른 창으로 이동하도록 기존 api 그대로 사용
-
새로고침, 뒤로가기, 앞으로가기, 로드 중지 등
-
일단 event.preventDefault 설정하지 말고 디폴트 설정 그대로 사용
-
TAB으로 focus된 화면 내의 조작 가능한 영역들(anchor, input, etc) 순회
-
선택된 a 태그를 엔터 입력으로 클릭
-
텍스트 선택 후 잘라내기/복사/붙여넣기
-
-
단축키: 구현 방법들과 각자의 특성
-
global shortcut : 운영체제에 단축키 등록.
-
문제점: 해당 앱이 선택되지 않은 상황에서도 실행됨. 다른 앱에 설정된 단축키를 덮어쓰게 됨.
-
응용: 운영체제에 global shortcut을 등록하고 제거하는 작업을 앱에 초점이 들어오고 나갈 때마다 반복
app.on('focus', registerAllGlobalShortcuts()) app.on('blur', globalShortcut.unregisterAll())
-
-
menu : 해당 앱에 초점이 맞춰진 상황에서만 실행 가능한 단축키 등록 가능. (권장사항)
- 초점이 맞추어진 browserWindow를 변수로 받아 작업 가능.
- 맥에서는 앱 외부의 상단의 메뉴를 클릭하여 단축키 목록 조회 및 실행 가능.
- 윈도우와 리눅스에서는 목록을 숨길 수 있음.
-
로드되는 파일 자체에 renderer로 이벤트리스너 추가: 가장 구체적인 방법.
-
webcontents에 사용자 입력에 대한 이벤트리스너 등록
-
주의. 창에 등록되는 것이 아니라 특정 webcontents에 focus가 간 상태에서만 동작. browserWindow에 초점이 간 경우, browserView에 등록된 단축키는 동작하지 않음.
-
주의: fn 없이 F1~F12 등의 function key를 실행할 수 있도록 운영체제가 설정된 경우 function key 입력 인식 불가능. (Mac)
// 모든 webcontents에 동일한 단축키 등록하는 예제 app.on('web-contents-created', function (event, wc) { wc.on('before-input-event', function (event, input) { if (input.key === 'x' && input.ctrl && !input.alt && !input.meta && !input.shift) { // Do something for Ctrl-X event.preventDefault() } }) })
-
-
-
windowId 필요 : 2번째 창을 여는 경우 ipcRenderer 중복 등록 문제 발생
-
탭을 무한 생성하고 focus tab을 제거하는 경우, 다음 focus tab id로 자기 자신을 선택하는 버그 - 구조 뜯어고칠 때 수정 누락됨
-
네트워크 불안정에 대한 예외처리 화면 추가
-
webContents.openDevTools()를 통해 개발자도구를 여는 경우 SyntaxError: Unexpected end of JSON input 경고문 출력
-
favicon 로드 실패에 대한 예외처리 필요
- 디폴트 탭 favicon을 대신 보여주기
- 이에 따라 복수의 favicon이 생성될 수 있는 상황 디버깅: 1개의 favicon만 존재하도록 cleanse
- favicon 로딩을 실패한 프로세스에서 omnibox에 url을 입력하는 경우, 앱 전체가 다운되는 문제
-
모든 기능에 대한 기기 호환성 체크 필요
-
더블 클릭 방지 : loading 여부에 따라 잠시 동안 조작 불가능하도록
-
메인 프로세스에서는 당연히 focusTabIdx 대신 focusTabId를 관리
-
이미 focus된 탭 클릭하는 경우 토글하는 것으로 간주하지 말기. 무의미한 재렌더링으로 인한 성능 저하.
-
cover up ugly border left of focus tab