바른 말씨 extension을 쓰면서 항상 아쉬웠고 구현하고자 하는 기능이 있었는데, 검사 후에 틀린 단어로 표시된 것을 어떻게 하면 제시된 해당 대치어로 쉽게 고쳐줄 수 있을까 하는 고민이었다.

처음엔 그냥 웹페이지에 표시된 틀린 단어에 마우스를 가져가면 tooltip 형태로 해당 대치어를 보여주는 방법을 구상해 보았지만, 또 막상 고치려면 수작업이 필요해서 마땅치 않았다. 그래서 구상한 것이 틀린 단어를 클릭하면 자동으로 해당 대치어로 바꿔주는 방법 쪽으로 고민해봤다.

우선 틀린 단어에 대한 대치어를 각각 따로 저장해 놓을 장소가 필요했는데, 여기엔 HTML5의 custom data attribute이 안성맞춤이다. 바른 말씨 extension에서 틀린 단어를 클릭하면 해당 대치어로 고쳐주는 것의 구현 방식(이)란 제목의 글 마저 읽기 →

오래전부터 웹사이트에선 RSS feeds의 관리와 구독자에 관한 통계 자료를 얻으려고 Google Analytics와 함께 FeedBurner를 많이 사용하고 있다.

이런 사이트의 RSS feed를 구독하고 새로운 글이 올라오면 feed 주소를 클릭해서 해당 페이지를 방문하는 일도 자연 많아졌는데, 문젠 이렇게 방문한 페이지의 주소를 책갈피에 등록하려고 보면 아래처럼 원래 주소 끝에 쓸데없는 것이 달라붙으면서 상당히 지저분하다는 것이다.

http://웹페이지_주소?utm_source=feedburner&utm_medium=feed&utm_campaign=…

이놈은 Google Analytics에서 사용하는 방문자의 접속 형태를 추적하려는 목적의 UTM(Urchin Tracking Module|Monitor) queries인데, 이런 현상은 Google Reader에서 구독한 feed URL을 클릭해서 타고 들어가도 마찬가지.

물론 이렇게 쓸데없이 길어진 주소는 Twitter와 같은 URL 공유 사이트를 사용할 때도 불편할 수밖에 없다.

어쩔 수 없이 이렇게 달라붙어 있는 놈은 일일이 손수 지우고 나서야 책갈피에 담아두던 주소 공유를 하던 마음이 편했는데, 너무 자주 있는 일이라 결국 이런 성가신 작업을 대신해주는 Safari, Chrome extension UTM 청소기를 만들게 되었다.

Safari 용 UTM 청소기, Chrome 용 UTM 청소기

자 이제 때 묻지 않은 순수한 URL 활용에 활력을.

Safari 5.1부터 지원하기 시작한 Popover 기능(Chrome에선 이 기능이 예전부터 있었으며 Popup이라고 불림) 덕분에 이젠 웹페이지에 있는 글뿐만 아니라 맞춤법 검사를 하고자 하는 글을 도구막대 버튼을 누르면 뜨는 작은 Popover/Popup 창에다 직접 입력해서 검사를 수행할 수 있게 되었다.

바른 말씨 Safari/Chrome 익스텐션의 검사 창 모습

겸사겸사 SafariChrome 익스텐션을 함께 갱신하게 되었는데 둘의 창 모양까지 닮았으니 Safari가 Chrome의 것을 많이 참고한 것 같지만, 그래도 개발 문서만은 Safari에게 더 후한 점수를 주고 싶다.

참고로, Safari와 Chrome의 Popovers/Popups 구현에는 약간의 차이가 있는데, Safari에선 웹페이지에서 글자를 선택하지 않은 경우에만 Popovers 창을 보여주지만, Chrome에선 popups 창 기능을 구현했을 때는 도구막대 버튼에 심어둔 onClicked event를 그냥 무시하고 무조건 Popups 창을 보여준다. 따라서 상황에 맞춰 웹페이지에서 선택한 글에 대한 검사 개시 방아쇠(trigger)로서 선택적으로 도구막대 버튼을 사용할 수 없게 되었다는 아쉬움이 있다. (이것은 manifest 파일에 popups html 파일을 지정하지 않은 채 setPopup() method를 써도 마찬가지.)

어차피 선택한 글에 대한 검사 개시의 방아쇠로 단축키(Option + Q/ㅂ) 혹은 Contextual 메뉴를 주로 쓰기 때문에 이에 따른 큰 불편은 없을 것이다.

웹에서 가끔 눈에 띄는 adf.ly나 linkbucks.com 서비스로 생성된 링크를 누르면 광고 페이지로 연결되면서 몇 초간 광고를 쳐다봐야만 원래 방문하려는 페이지로 이동할 수가 있는데, 물론 자주는 아니지만, 막상 닥치면 이런 잠깐의 기다림도 성가시고 불필요한 시간 소비로 느껴질 수밖에 없다.

그래서 이런 불편을 덜고자 하는 생각이 또 하나의 익스텐션 아이디어로 발전하면서 광고 넘김이가 만들어졌다.

원리는 아주 간단해서, 광고를 보여주는 페이지에 있는 원래 방문하려는 페이지의 주소를 가져다 document.location 값에 전달해서 바로 이동하게 하는 구조. 물론, 이렇게 간단한 꼼수를 부렸기 때문에 광고 페이지에 있는 JavaScript 구현 방식이라도 바뀌면 거기에 맞는 수정이 필요하다.

가장 큰 난관은 각 서비스로 연결된 공개되지 않은 은밀한 사이트의 주소가 알고 보니 한두 개가 아니었는데, 이미 나와 있는 비슷한 기능의 Google Chrome extension인 Linkbucks skip과 UserScripts에 공개된 AdsFight! for Greasemonkey에서 그 목록을 확보할 수 있었다.

앞으로 비슷한 다른 서비스 지원은 보이는 대로 추가할 예정.

Safari extension으로 먼저 나온 바른 말씨Google Chrome 용으로도 배포할 목적으로 개발하면서 부딪혔던 문제로, 대부분의 extension APIs와 그 구조는 서로 닮았기 때문에 코드 이전에는 별다른 어려움은 없었다. 그런데 한 가지 커다란 장벽과 마주쳤으니.

보통 extensions에 의해 페이지에 삽입되는 Content Scripts는 독립적인 sandbox 환경에서 실행되면서 원래 웹 페이지에 존재하는 스크립트와의 간섭을 걱정할 필요 없이 DOM을 만질 수 있게 되는데, 불행히도 Google Chrome extensions에선 iframes 접근이 차단되어 있어서 window.frames 값으로 undefined를 돌려준다. 이 문제는 알려진 버그로, 해결책으로 다음과 같이 Background Page에서 chrome.tabs.executeScript() 명령으로 해당 사이트의 DOM에다 직접 script tag을 생성해서 Chrome의 Sandbox 밖에서 실행되는 스크립트를 삽입해 주는 것이다.

chrome.tabs.executeScript(null, {file: 'scriptInjecting.js'}, scriptInjected);

script tag를 만들고 Sandbox를 탈출해서 실행될 스크립트를 삽입하는 scriptInjecting.js 파일의 내용은 다음과 같다.

(function(doc) {
  var s = doc.createElement('script');
  s.type = 'text/javascript';
  s.src = chrome.extension.getURL("escapedFromChromeSandbox.js");
  var x = doc.getElementsByTagName('script')[0];
  x.parentNode.insertBefore(s, x);
})(document);

이렇게 해서 삽입된 escapedFromChromeSandbox.js 파일에선 iframes의 속 내용을 들여다볼 수 있게 된다.

여기서 얻어진 정보는 가령, hidden input을 만들고 이놈의 value나 title 혹은 data 속성에다가 저장해 놓기만 하면, 나머진 종전처럼 해당 페이지의 DOM 접근이 가능한 Content Scripts에서 이곳에 저장된 정보를 읽고 message passing을 통해 background pages에 전달해주면 된다.

이 밖에도 사소한 것으로, 검사 결과를 보여주는 창을 마우스로 잡아서 이동시킬 수 있도록 하는 기능을 구현하는데, Safari에선 별문제 없던, HTML5의 Drag and Drop 기능을 빌려 쓰려 하였으나 drag시 마우스의 위치 값을 제대로 돌려받지 못하는 문제도 있어서 결국 약간 소모적일 수도 있는 Mouse events를 써야만 했다.

최근 많은 브라우저가 extensions 혹은 add-ons 형태로 사용자 입맛에 맞는 추가 기능을 제공하는 추세이고 또 각 브라우저가 가지고 있는 고유 API와 그 구현 방식도 서로의 차이점이 줄어들고 있기는 하지만, 아직은 개발자에게 혼동을 일으킬 수 있는 미묘한 차이를 보이면서 앞으로 어떤 통합된 개발 환경이 제공되었으면 하는 바람도 가지게 된다.