ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 웹브라우저 확장기능 개발.
    프로그래밍/Web 2018.12.31 06:56

    요렇게 스토어 등록했습니다.[각주:1]

    Readable Font - Get this Extension for 🦊 Firefox (ko)

    Download Readable Font for Firefox. 가독성 좋은 글씨를 보여줍니다.

    Readable Font

    가독성 좋은 글씨를 보여줍니다.

    Readable Font - 웨일 스토어

    가독성 좋은 글씨를 보여줍니다.

    웹브라우저 폰트 관련 확장기능을 만들었는데, 그 과정을 공유해서 아이디어는 있는데 개발을 어떻게 해야할지 우왕좌왕 싶은 분들에게 일종의 가이드(?)를 해주려 합니다.

    * 확장기능은 부기기능, 확장앱, Addon, Extension 등으로도 부릅니다.


    처음 만들어봤는데 생각보다 쉬워요^^[각주:2]

    단, 제가 하는 강좌는 HTML, CSS, Javascript 강좌가 아니고 저도 막 익숙하다고 말하기가 그래서.. 해당 내용에 대한 설명은 넘어가는걸루.


    전체 코드가 담긴 깃허브를 참고하면서 보세요.

    black7375/Readable_Font

    View Pretty Font on Web Browser!! Contribute to black7375/Readable_Font development by creating an account on GitHub.


    참고로 이 글에서 보여주는 코드는 릴리즈 1.1.0 기준입니다.

    src/Readable Font/를 참고.


    - 참고 할 만한 문서 및 예제.

    문서: MDN, Chrome, Opera, Whale(한글), Edge.

    예제: 파이어폭스, 크롬, Opera, Edge.

    0. 아이디어.

    무언가를 만들려면 아이디어와 목표, 기획이 있어야겠죠?

    저희의 목표는 요렇게 만드는 것입니다.

    제가 만든 블로그 스킨(Letter - Enhanced)과 디자인이 유사합니다.ㅎ

    블로그 스킨에 들어가는 기능과 부가기능에 들어가는 기능은 서로 영향을 주고 받으며 클거에요.


    들어가는 기능들을 살펴보자면



    1. 디자인 구현하기.

    제 성격 탓인지, 일단 눈에 보이는 것을 어느 정도 만들어놓고, 기능을 추가해야  속이 편하더군요.

    무언가를 했다는 성취감이 그나마 듭니다. ㅋㅋ


    우선 토글 버튼부터 만들어봅시다.

    토글 버튼의 정체가 과연 뭘까요?


    바로 체크박스 입니다.

    체크를 했다(ON), 풀었다(OFF) 상태를 오가죠.


    우선 팝업을 만들테니, popup.html을 생성해봅시다.

    popup.html

    < !doctype html> 
    <html>

    <head>
    <title>Toogle Design</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="./toggle.css" type="text/css" />
    </head>

    <body>
    <h1>Toogle Design</h1>
    <div class="toggle">
    <h2>설정내용.
    <input type="checkbox" class="toggle_checkbox"></h2>
    </div>
    </body>

    </html>


    웹브라우저로 켜서 확인해보면 황량하기 그지 없습니다 ㅠㅠㅠ

    무슨 오류인지는 모르겠는데 첫줄에 <표시 후에 바로 문자가 있으면 빈줄로 표시되네요.

    그래서 한칸씩 띕니다.

    이걸로 뭐하라고..

    이때 필요한 것이 바로바로 CSS입니다.


    CSS를 적용해서 꾸며야 하는데, 체크박스를 바로 꾸밀 수 있는가?

    아닙니다.


    그래서 저희는 label을 통해 우회적으로 돌아갑니다.

    < body>
    <h1>Toogle Design</h1>
    <div class="toggle">
    <h2>설정내용.
    <input type="checkbox" id="setting" class="toggle_checkbox">
    <label class="toggle_btn" for="setting"></label></h2>
    </div>
    </body>

    for을 통해 체크박스의 id를 공유함으로서 라벨을 누르면 체크박스를 누르는 것과 같은 효과가 생깁니다.


    그 후, CSS를 적용해봅니다.

    toggle.css

    /* =====================================================
    Toggle Button's CSS
    ===================================================== */
    *,
    *::before,
    *::after
    {
    box-sizing: border-box;
    }

    .toggle
    {
    display: block;
    margin-top: 40px;
    user-select: none;
    position: relative;
    }

    .toggle_checkbox
    {
    display: none;
    }

    .toggle_btn
    {
    display: inline-block;
    float: right;
    font-size: 1.4em;
    transition: all 350ms ease-in;
    position: relative;
    height: 35px;
    width: 60px;
    border-radius: 70px;
    background-color: #e25d5d;
    border: 5px solid #ad1000;
    }

    .toggle_btn:hover
    {
    cursor: pointer;
    }

    .toggle_btn,
    .toggle_checkbox,
    .toggle_feature,
    .toggle_btn:before,
    .toggle_checkbox:before,
    .toggle_feature:before,
    .toggle_btn:after,
    .toggle_checkbox:after,
    .toggle_feature:after
    {
    transition: all 250ms ease-in;
    }

    .toggle_btn:before,
    .toggle_checkbox:before,
    .toggle_feature:before,
    .toggle_btn:after,
    .toggle_checkbox:after,
    .toggle_feature:after
    {
    content: '';
    display: block;
    }

    .toggle_btn:before
    {
    position: absolute;
    width: 25px;
    height: 25px;
    border-radius: 50%;
    background-color: #f2dd68;
    border: 5px solid #e5ce5e;
    }

    .toggle_checkbox:checked+.toggle_btn
    {
    border: 5px solid #0865b0;
    background-color: #3498db;
    }

    .toggle_checkbox:checked+.toggle_btn:before
    {
    transform: translate(25px, 0);
    }

    엄청 간단하게 설명하자면,

    체크박스는 안보이게 숨겨놓고, 빨간 배경에 노란 원을 띄우다가 라벨을 눌러 체크박스가 체크된 상태라면 배경은 파란색으로 바뀌고 노란 원은 오른쪽으로 25px만큼 움직이라는 뜻입니다.


    휴.. 이제 마음의 안정이 찾아왔습니다.


    본격적으로 개발에 들어가보도록 하죠.


    2. 매니페스트(Manifest) 작성.

    매니페스트는 확장기능의 이름, 버전, 아이콘 등의 메타 데이터,  동작을 위한 설정, 권한등을 적어놓는 JSON파일입니다.


    주요 manifest.json[각주:3] 구조는 다음과 같습니다.(모든 것을 살펴보려면 링크로)

    {
    //==========설명==========
    //필수
    "name": "확장기능 이름",
    "version": "버전",
    "manifest_version": 2,

    //기타설명
    "description": "확장기능 설명",
    "icons": {
    "16": "아이콘1",
    "48": "아이콘2",
    "128": "아이콘3"
    },
    "homepage_url": "https://example.org/my-addon",

    //==========기능==========
    //주요기능
    "browser_action": {
    "default_title": "제목",
    "default_popup": "팝업.html",
    "default_icon": "아이콘"
    },

    "page_action": {
    "default_title": "제목",
    "default_icon": "아이콘",
    "default_popup": "팝업.html",
    "browser_style": true
    },

    "sidebar_action": {
    "default_title": "제목",
    "default_icon": "아이콘",
    "default_panel": "사이드바.html",
    "open_at_install":true
    },

    //선택기능
    "background": {
    //둘중 하나
    "scripts": ["스크립트1.js", "스크립트2.js", ...],
    "page": "페이지.html"
    }

    "content_scripts": [{
    "matches": ["*://*.mozilla.org/*", ...],
    "css": ["컨텐츠1.css", "컨텐츠2.css", ...],
    "js": ["컨텐츠1.js", "컨텐츠2.js", ...],
    "run_at": "실행시점 - 아래서 설명"
    }],

    "options_ui": {
    "page": "옵션.html"
    },

    //==========권한==========
    "permissions": [
    "storage",
    "*://developer.mozilla.org/*"
    ],

    "web_accessible_resources": ["리소스1", "리소스2", ...]
    }


    원래 json 파일엔 주석표시(//)는 없어야 정상이지만.. 설명하려는 거니까 .


    2.1 설명.

    필수적으로 필요한 것은 확장기능의 이름, 버전, 매니페스트 버전입니다.

    매니페스트 버전은 그냥 2고정으로 사용하면 됩니다.


    아이콘은 대부분 16x16, 48x48, 128x128 3개를 사용하는데, 32x32, 64x64를 사용하는 경우도 있습니다. 알아서 만드세요 ㅋㅋ


    전 이렇게 만들었습니다.(16x16, 32x32, 128x128)



    2.2 기능.

    2.2.1 주요기능.

    주요기능은 browser_action, page_action, sidebar_action으로 나뉘어져 있습니다.


    브라우저 액션은 툴바에.

    Browser Action[from  User interface]


    페이지 액션은 주소창에.

    Page Action[from  User interface]


    사이드바 액션은 사이드바로.

    Sidebar Action[from  User interface]


    아! default_popup대신 버튼처럼 사용해도 되는거 아시죠?


    2.2.2 선택기능.

    - Background

    background는 특정한 페이지(탭)이나 윈도우(창)에 묶이지 않는 백그라운드 프로세스를 생성하는 것으로 창과 독립적으로 장기적인 작업을 할 때 어울리는 기능입니다.

    scripts 또는 page 중 하나를 선택해야 하는데 page의 경우 ES6를 지원한다는 장점이 있다.

    * 모든 Web Extension API를 사용할 수 있음.


    - Content Scripts

    content_scripts는 웹페이지에 주입하기 위한 기능입니다.

    DOM 조작이 가능하지만, 삽입된 웹 페이지 내에 정의된 JS 변수, 함수에 접근할 수 없고 API에는 제한이 있습니다.


    사용가능한 API 목록.

    접근할 수 없는 API에는 background와의 메세지교환을 통해 우회적으로 접근할 수 있습니다.


    matches는 말 그대로 적용될 사이트나 대상을 선택하는 것으로 Match patterns in extension manifests를 참고하세요.


    드디어 run_at을 설명할 때가 됐네요.

    이 옵션은 js에 지정된 스크립트가 주입되는 시기를 결정합니다.

    • "document_start": 로딩될 때. DOM이 아직 로드 중입니다.
    • "document_end":  DOM 로드 후. DOM 로드가 완료되었지만 스크립트나 이미지와 같은 리소스가 로드 중 일 수 있습니다.
    • "document_idle": 완료 될 때. 웹문서 및 모든 리소스의 로드가 완료 시.


    - Options UI

    options_ui는 말 그대로 설정 UI를 만드는 것 입니다.


    Options UI[from  User interface]

    options_page라고

    "options_page": "옵션.html"

    옵션 페이지를 만드는 것도 있는데,  Deprecated(더 이상 사용되지 않는) 상태이므로 사용하지 맙시다. 무엇보다 파이어폭스에서 지원을 안 하며 크롬 계열에선 옵션 창이 새 탭에서 뜬다.


    2.3 권한.

    - Permission

    Permission의 종류는 크게 두가지로 나뉘어진다.

    아까 나왔던 매치 패턴브라우저 API.


    - Web Accessible Resources

    Web Accessible Resources는 웹페이지에서 접근하여 사용하려는 리소스를 등록하는 용도입니다.


    2.4 정리.

    그림으로 보면 깔-끔.

    정리하고 갑시다.

    그림으로 보는 파일구조[from Anatomy of an Extention]


    2.5 제 매니페스트.

    manifest.json

    {
      "name": "Readable Font",
      "version": "1.1.0",
      "manifest_version": 2,
    
      "description": "가독성 좋은 글씨를 보여줍니다.",
      "icons": {
        "16":  "icon@16.png",
        "32":  "icon@32.png",
        "128": "icon@128.png"
      },
    
      "browser_action": {
        "default_title": "Readable Font",
        "default_popup": "popup/popup.html",
        "default_icon":  "icon@16.png"
      },
    
      "content_scripts": [{
        "all_frames": true,
        "match_about_blank": true,
        "matches": ["< all_urls>"],
        "run_at": "document_start",
        "js": ["contents/content.js"]
      }],
    
      "permissions": [
        "storage",
        "< all_urls>"
      ],
    
      "web_accessible_resources": ["contents/*.css", "contents/*.woff2"],
    
      "options_ui": {
        "page": "options/options.html"
      }
    }

    역시 하이라이터 오류로 all부분의 앞에 스페이스 처리했으니 이해해주세요.


    3. 추가 디자인 구현 및 디버깅.

    3.1 디자인 구현.

    html과 css를 사용하여 popup과 option 화면을 만들었습니다.


    팝업화면.



    popup.html

    < !doctype html>
    <html>
    
    <head>
    <title>Readable Font</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="../contents/substitue.css" type="text/css" media="screen" />
    <link rel="stylesheet" href="./popup.css" type="text/css" />
    <link rel="stylesheet" href="../lib/toggle.css" type="text/css" />
    </head>
    
    <body id="mainPopup">
    <div id="title">Readable Font</div>
    <div class="toggle">
      <h2>선명하게
        <input type="checkbox" id="font_sharpen" class="toggle_checkbox">
        <label class="toggle_btn" for="font_sharpen"></label></h2>
      </div>
      <div class="toggle">
      <h2>글꼴치환
        <input type="checkbox" id="font_substitue" class="toggle_checkbox">
        <label class="toggle_btn" for="font_substitue"></label></h2>
      </div>
      <div class="toggle">
      <h2>수식표현
        <input type="checkbox" id="font_math" class="toggle_checkbox">
        <label class="toggle_btn" for="font_math"></label></h2>
      </div>
      <script type="text/javascript" src="./popup.js"></script>
      <script type="text/javascript" src="../lib/checkbox.js"></script>
    </body>
    
    </html>
    

    popup.css

    #mainPopup
    {
      padding:    10px;
      height:     200px;
      width:      250px;
      overflow-y: scroll;
      overflow-x: hidden;
    }
    
    #title
    {
      text-align:  center;
      font-size:   23px;
      font-weight: 900;
      font-family: "Noto Serif", serif;
    }
    
    h2
    {
      font-size:   24px;
      font-weight: 900;
      font-family: "Noto Sans", sans-serif;
    }
    

    옵션화면.



    options.html

    < !doctype html>
    <html>
    
    <head>
    <title>Readable Font</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="../contents/substitue.css" type="text/css" media="screen" />
    <link rel="stylesheet" href="./options.css" type="text/css" />
    <link rel="stylesheet" href="../lib/toggle.css" type="text/css" />
    </head>
    
    <body>
    <div id="title">Readable Font</div>
    
    <h1>선명하게</h1>
    <div class="toggle">
      <h2>저해상도 기기 최적화
        <input type="checkbox" id="font_subpixel" class="toggle_checkbox">
        <label class="toggle_btn" for="font_subpixel"></label></h2>
      </div>
      <p>선명하게 기술에서 쓰이는 안티얼라이싱은 저해상도 기기에서 흐릿하게 보일 수도 있습니다.</p>
      <p>저해상도 기기 최적화 옵션을 활성화하면 서브픽셀 렌더링을 사용합니다.</p>
      <div class="toggle">
      <h2>가독성 향상
        <input type="checkbox" id="font_legibility" class="toggle_checkbox">
        <label class="toggle_btn" for="font_legibility"></label></h2>
      </div>
      <p>글씨의 합자(ligatures)와 간격조정(kerning) 기능을 활성화 시켜 가독성을 개선합니다.</p>
      <p>글꼴의 렌더링 옵션을 수정하는 것이므로 글씨의 간격이 일부 변형될 수 도 있습니다.</p>
      <br>
      <h1>글꼴치환</h1>
      <div class="toggle">
      <h2>향상된 글꼴
        <input type="checkbox" id="font_better" class="toggle_checkbox">
        <label class="toggle_btn" for="font_better"></label></h2>
      </div>
      <p>못생긴 글꼴을 비슷한 느낌이지만, 더 나은 글꼴로 대체합니다.</p>
      <div class="toggle">
      <h2>비슷한 글꼴
        <input type="checkbox" id="font_alter" class="toggle_checkbox">
        <label class="toggle_btn" for="font_alter"></label></h2>
        </div>
        <p>화면에 표시 될 글꼴이 없을 경우, 유사한 글꼴을 보여줍니다.</p>
        <br>
        <h1>수식표현</h1>
        <div class="toggle">
          <h2>MathJax
            <input type="checkbox" id="font_mathjax" class="toggle_checkbox">
            <label class="toggle_btn" for="font_mathjax"></label></h2>
          </div>
          <p>MathML(수식 표현 체계중 하나)를 크롬계열 브라우저에서는 지원하지 않습니다.</p>
          <p>MathML이 포함된 문서가 있으면 MathJax를 로드하여 보여줍니다.</p>
          <br>
          <h1>License</h1>
          <h2 id="readable">Readable Font</h2>
          ...이하생략
          <script type="text/javascript" src="./options.js"></script>
          <script type="text/javascript" src="../lib/checkbox.js"></script>
    </body>
    
    </html>


    options.css

    #title {
      text-align:  center;
      font-size:   30px;
      font-weight: 900;
      font-family: "Noto Serif", serif;
    }
    
    #readable {
      font-family: "Noto Serif", serif;
    }
    
    body {
      margin: 20px 20px;
    }
    
    table,
    h1,
    h2,
    p {
      font-family: "Noto Sans", sans-serif;
    }
    
    h1 {
      font-size:   30px;
      font-weight: 900;
    }
    
    h1::after {
      content:    '';
      display:    block;
      margin-top: 15px;
      border-top: 1.5px solid #9A9A9A;
    }
    
    table,
    h2 {
      font-size:   24px;
      font-weight: 800;
    }
    
    p {
      font-size: 16px;
    }
    
    pre {
      font-size:   12px;
      font-family: "D2 Coding", monospace;
    }
    

    3.2 디버깅.

    디버깅이라 쓰고, 확인하기입니다.


    파이어폭스에

    'about:debugging'을 치고 들어가서 '임시 부가기능 로드중...'을 누른 후, manifest.json 파일을 로드합니다.


    그 후 '디버그' 버튼을 누르면 확장 기능과 관련된 화면이 나오거나 기능이 동작할 시

    디버깅 도구에 내용이 표시됩니다.


    자바스크립트 같은 경우 console.log("Hi") 같은 기능을 적절히 이용해가며 디버깅하세요.


    4. 기능 코딩.

    자바스크립트를 사용해서 본격적으로 코딩해봅시다.


    4.1 체크박스 상태 로딩 및 저장.

    먼저 할 것은 팝업과 옵션 페이지를 열었을 때 체크박스의 옵션 상태를 로딩하고,

    변경점이 생기면 저장을 하는 것 입니다.


    옵션 상태를 로딩 및 저장해주는 기능을 하는 checkbox.js와 각 옵션을 정의해주는 popup.js, options.js로 나뉘어 있습니다.

    checkbox.js

    /*jshint esversion: 6 */
    /* =====================================================
     Checkbox Load && Storage
     ===================================================== */
    var storage = chrome.storage.local;
    
    function get_checkbox(id)
    {
      var check = document.getElementById(id);
      return check.checked;
    }
    
    function set_checkbox(id, value)
    {
      var check     = document.getElementById(id);
      check.checked = value;
    }
    
    function load_checkbox(id)
    {
      var state = id.substring(5);
      storage.get(state, (option) => {
        set_checkbox(id, option[state]);
      });
    }
    
    function toggle_storage(id)
    {
      var state = id.substring(5);
      if (get_checkbox(id))
        storage.set({[state]: true});
      else
        storage.set({[state]: false});
    }
    
    function click_check(id)
    {
      var font = document.getElementById(id);
      font.addEventListener("click", function() {
        toggle_storage(id);
      });
    }
    
    window.addEventListener('load', () => {
      id_callback(load_checkbox);
      id_callback(click_check);
    });

    - 로딩.

    window.addEventListener()

    팝업 또는 옵션페이지가 로드될 때 각 옵션의 id값에 따라 체크박스를 로드, 체크하는 기능을 활성화.

    팝업과 옵션페이지의 자바스크립트 파일에 id_callback를 정의해 해당되는 id를 설정해주면 됩니다.

    popup.html과 options.html에서 font_sharpen, font_subpixel처럼 정의한 적이 있었죠?


    load_checkbox()

    id의 font_ 부분은 제거한게 옵션 이름입니다.

    옵션이름으로 저장된 상태를 가져온 뒤 set_checkbox를 사용해 체크박스에 저장된 상태를 적용시킵니다.


    set_checkbox()

    입력받은 id에 대응되는 체크박스에 입력받은 상태를 적용시킵니다.


    - 상태 확인 및 저장.

    click_check

    옵션 id에 클릭 이벤트가 발생시 toggle 시킵니다.


    https://black7375.tumblr.com/post/180591204720/확장기능-만들-때-주의할-점

    toggle_storage()

    입력받은 id에 대응되는 체크박스 상태를 확인(get_checkbox)하고 반전시킵니다.


    get_checkbox()

    입력받은 id에 대응되는 체크박스 상태를 반환합니다.


    * 보다보니.. 몇개 작명이 잘못된 듯 싶다.

    set_checkbox의 value를 state로,

    click_check의 font는 check로 고쳐야겠다.


    그럼 id_callback이 있는 popup.js와 options.js를 보도록 합시다.


    popup.js

    /*jshint esversion: 6 */
    
    function id_callback(callback)
    {
      if(callback && typeof(callback) === "function")
      {
        callback("font_sharpen");
        callback("font_substitue");
        callback("font_math");
      }
    }

    보다시피 엄청 간단합니다.

    - 콜백.

    id_callback()

    콜백으로 들어오는 인자값이 함수인지 확인 후 font_sharpen, font_substitue, font_math에 대한 체크박스 동작(checkbox.js) 활성화.


    options.js

    /*jshint esversion: 6 */
    var storage = chrome.storage.local;
    
    var options = {
      legibility: true,
      better:     true,
      mathjax:    true
    };
    var optionList = Object.keys(options);
    
    function init_options()
    {
      optionList.forEach((option) => {
        storage.get(option, (state) => {
          if(typeof(state[option]) === "undefined" || state[option] === null)
            storage.set(options);
        });
      });
    }
    
    function id_callback(callback)
    {
      if(callback && typeof(callback) === "function")
      {
        callback("font_subpixel");
        callback("font_legibility");
    
        callback("font_better");
        callback("font_alter");
    
        callback("font_mathjax");
      }
    }
    
    window.addEventListener('load', () => {
      init_options();
    });

    options.js는 popup.js에 비하여 조금 깁니다.

    이유는 초기설정값을 지정해주기 때문입니다.


    - 초기값 설정.

    window.addEventListener()

    로드 될 때 초기 옵션 값을 체크합니다.

    options

    json 형태로 초기값을 설정해놨습니다.


    optionList

    Object.keys()를 사용하여 for..in문 형태로 사용하도록 합니다.


    init_options()

    각 옵션의 상태가 정의되지 않았거나 null 값인 경우 options의 값을 사용합니다.


    4.2 옵션 상태에 따른 CSS 주입.

    이건 content.js가 담당하고 있습니다.


    content.js

    /*jshint esversion: 6 */
    //====================basic
    var storage = chrome.storage.local;
    
    function load_css(file)
    {
      var link   = document.createElement("link");
      link.href  = chrome.extension.getURL('contents/' + file + '.css');
      link.rel   = "stylesheet";
      link.type  = "text/css";
      link.media = "screen";
      link.id    = file;
      document.getElementsByTagName("html")[0].appendChild(link);
    }
    
    function unload(file)
    {
      var node = document.getElementById(file);
      if (node)
        node.parentNode.removeChild(node);
    }
    
    function on_off(file, loadCallback, unloadCallback, loadOption, unloadOption)
    {
      storage.get(file, (option) => {
        if (option[file])
        {
          if(loadCallback && typeof(loadCallback) === "function")
          {
            loadCallback(file);
            if(loadOption && typeof(loadOption) === "function")
              loadOption(file);
            if(file === "subpixel")
              unload("sharpen");
            if(file === "mathjax")
              load_mathjax();
          }
        } else
        {
          if(unloadCallback && typeof(unloadCallback) === "function")
          {
            unloadCallback(file);
            if(unloadOption && typeof(unloadOption) === "function")
              unloadOption(file);
          }
        }
      });
    }
    
    function check(file)
    {
      on_off(file, load_css, unload, load_option, unload_option);
    }
    
    function update()
    {
      check("sharpen");
      check("substitue");
      check("math");
    }
    window.addEventListener('load',update);
    chrome.storage.onChanged.addListener(update);
    
    //====================options
    var feature = {
      sharpen:   ["subpixel", "legibility"],
      substitue: ["better", "alter"],
      math:      ["mathjax"]
    };
    
    function load_option(file)
    {
      feature[file].forEach((option) => {
        on_off(option, load_css, unload);
      });
    }
    
    function unload_option(file)
    {
      feature[file].forEach((option) => {
        unload(option);
      });
    }
    
    function load_mathjax()
    {
      if((window.unsafeWindow == null ? window : unsafeWindow).MathJax == null)
      {
        if((document.getElementsByTagName("math").length > 0) ||
           (document.getElementsByTagNameNS ==  null ? false :
            (document.getElementsByTagNameNS("http://www.w3.org/1998/Math/MathML","math").length > 0)))
        {
          var  head   = document.getElementsByTagName("head")[0];
          var script  = document.createElement("script");
          script.type = "text/x-mathjax-config";
          script[(window.opera ? "innerHTML" : "text")] =
            "  MathJax.Hub.Config({\n" +
            "  \"HTML-CSS\": {\n" +
            "    messageStyle: \"normal\",\n" +
            "    linebreaks: {\n" +
            "      automatic: false\n" +
            "    },\n" +
            "    undefinedFamily: \"'STIX Two Math', STIXGeneral, 'Arial Unicode MS', 'Noto Serif KR', serif\"\n" +
            "  },\n" +
            "  config: [\"MMLorHTML.js\"],\n" +
            "  jax: [\"input/TeX\",\"input/MathML\",\"output/HTML-CSS\",\"output/NativeMML\"],\n" +
            "  extensions: [\"tex2jax.js\",\"mml2jax.js\",\"MathMenu.js\",\"MathZoom.js\"],\n" +
            "  TeX: {\n" +
            "    extensions: [\"AMSmath.js\",\"AMSsymbols.js\",\"noErrors.js\",\"noUndefined.js\"]\n" +
            "  }\n" +
            "});";
          head.appendChild(script);
    
          script       = document.createElement("script");
          script.async = "";
          script.type  = "text/javascript";
          script.src   = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML-AM_HTMLorMML";
          script.id    = "mathjax";
          head.appendChild(script);
        }
      }
    }

    Basic.

    기본적인 기능들에 대해서 알아봅시다.


    - 이벤트.

    window.addEventListener()

    페이지가 로드될 때 업데이트하라고 지시한다.


    chrome.storage.onChanged.addListener()

    스토리지에 변경점이 생길때 업데이트 하도록 한다.

    스토리지에 변경점이란 앞서 popup과 option에서 On/Off등을 하며 값을 수정할 때겠죠?


    - 업데이트.

    update()

    글꼴들의 선명하게, 치환, 수식 기능을 점검.


    check()

    on_off 함수에 update에 해당하는 값과 각종 함수들을 넣어서 전해주는 Wrapper입니다.


    on_off()

    update, check를 통해 전한 값의 상태가 참이면 load, 거짓이면 unload 합니다.

    참 동작: 해당하는 load_css(), load_option(), 각종 예외사항을 적용

    거짓 동작: unload(), unload_option() 수행


    지금보니까 on_off 쪽은 수정해야 할 것이 조금씩 보인다. -_-

    나중에 업뎃할만한 결심이 서면 수정해봐야 할 듯.


    load_css()

    html 문서에 해당하는 css를 삽입.


    unload()

    해당하는 id를 제거.


    Options

    - 업데이트 옵션.

    feature

    각 기능의 옵션에 대해 명시해놓은 곳입니다.


    load_option()

    feature를 참고하여 옵션의 값을 체크하여 on/off 동작을 수행합니다.


    unload_option()

    feature를 참고하여 옵션을 비활성화 합니다.


    load_mathjax()

    math 태그가 있을때만 동적으로 로드합니다.

    MathJax.Hub.Config 부분은 Mathjax 설정.


    나름 쉽죠?

    확장 기능을 만들 때 꼭 도움이 되었으면 좋겠습니다.

    1. MS Edge용에도 등록할까 했는데.. 돈내놓으라고 하길래 빠른 포기.
      유료 프로그램도 아니고, 공짜 프로그램인데 굳~~이 내돈 들일 필요가 있나 싶더란. [본문으로]
    2. 덕분에 web 프로그래밍 코드 컨벤션 따윈 모르고 내마음 가는대로 작성ㅋㅋ
      개인 플젝이라 상관없긴 하다. [본문으로]
    3. 이 문서는 MDN을 참고하여 만들어졌습니다.
      MDN을 참고하는 이유는.. 구글,MS,삼성,W3C가 웹 기술문서를 모질라의 MDN에 통합 결정!으로 기술문서가 가장 풍부하기 때문!! [본문으로]

    댓글 0

Designed by black7375.