[Hack Time] Cuối tuần tập viết Extension cho Chrome

Câu chuyện là cuối tuần vừa rồi trong lúc đang rảnh rảnh ngồi suy nghĩ, mình thấy là một lập trình viên thì không nên ngừng trau dồi kiến thức và làm mới bản thân bằng cách Hack một cái gì đó. Và rồi mình tự đặt ra cho bản thân 1 khoảng thời gian vào cuối tuần, gọi là Hack Time.

Hack time là gì?

Mình đã tự đặt ra định nghĩa và nguyên tắc cho Hack time như sau:

  • Là khoảng thời gian để tạo ra 1 sản phẩm mới hoàn chỉnh và có thể chạy được ở môi trường production
  • Thời gian hoàn thành sản phẩm phải ngắn, tối đa là 48 tiếng, tối thiểu là 2 tiếng
  • Bế quan tỏa cảng trong thời gian này, tập trung hết khả năng của bản thân
  • Sản phẩm làm ra nên có tính thực tiễn cao, không giúp ích được cho người khác thì ít nhất cũng phải giúp ích cho bản thân
  • Khuyến khích học một ngôn ngữ/quy trình gì mới.

Ý tưởng

Dạo này mình muốn tập viết cái Extension cho Chrome mà chưa có thời gian tìm hiểu, tranh thủ cuối tuần rảnh rỗi ngồi mày mò xem sao. Cái Extension mình định viết cho Chrome tên là Giphy Loader, mô tả về cái Giphy Loader của mình một chút:

  • Extension mình viết bao gồm một input nhập từ khóa miêu tả ảnh Gifs
  • 2 cái button Get Image và Copy Image, đầu tiên chỉ hiển thị button get image thôi, sau khi load thành công gif image thì button coppy image mới hiển thị.
  • Sau khi nhập từ khóa vào input, click vào get image nó sẽ ramdom trả về một ảnh gif bất kỳ từ giphy.com về nội dung từ khóa miêu tả. Sau đó mình cho nó hiển thị phía bên dưới button.
  • Click vào vào copy image nó sẽ copy link của hình ảnh gif đó vào clipboard .
[Hack Time] Cuối tuần tập viết Extension cho Chrome
[Hack Time] Cuối tuần tập viết Extension cho Chrome

Mục đích của Extension này à… Umh… các ông biết là cái nghề lập trình rất là nhiều áp lực, căng thẳng và mệt mỏi đúng không? Thế cho nên là khi nào mà stress quá thì dừng tay ngắm gái một tí cho bớt căng não đi,  nó căng chỗ khác chẳng hạn..lol ??

Click to view image

Đùa chút thôi mục đích cốt yếu là Học cách viết 1 extension cho Chrome nhằm trau dồi kiến thức cho bản thân là chính.

OK, sơ qua là thế, giờ bắt đầu bắt tay vào làm thôi.

Xem thêm:

Code

Thực ra thì cứ nghĩ là viết được một cái extension khó khăn vất vả lắm nhưng thực ra thì bạn chỉ cần nắm vững html + css + js là xong ngay thôi.

Đầu tiên bạn tạo 1 thư mục để chứa các file. Sau đó tạo một file có tên là manifest.json (Chrome  có hiểu được extension bạn viết hay không là do file này, đây sẽ là file config cho extension của bạn). Nội dung sẽ là như sau:

 {
     // Required
     "manifest_version": 2,
     "name": "Giphy Loader",
     "version": "0.1",

     // Recommended 
     "description": "Random load gif image from giphy.com",
     "icons": {
         "16": "images/icon16.png",
         "48": "images/icon48.png",
         "128": "images/icon128.png"
     },
     "browser_action": {
         "default_icon": "images/icon16.png",
         "default_popup": "page/popup.html"
     },
     "permissions": [
         "http://api.giphy.com/"
     ],
     "homepage_url": "https://ntcde.com/"
 }

Sơ qua về cái file trên một chút:

  1. manifest_version: là version chrome extension bạn sử dụng (hiện nay là version 2).
  2. name: Đây là tên của extension trên Chrome.
  3. version: Phiên bản của extenssion.
  4. description: Mô tả cho extension.
  5. icons: Icons đại diện cho extension, app, hoặc theme, bạn nên có 3 kích cỡ 16px, 48px, 128px.
  6. browser_action: Dùng để tùy chỉnh icon, popup, tooltip, …
  7. permissions: liệt kê các quyền mà extension của bạn muốn sử dụng, khai báo các url website mà muốn nó chạy và các quyền.
  8. homepage_url: Đây là trang web của nhà phát triển, mình để là website mình, cái này bạn có thể bỏ.

Bạn có thể tham khảo Manifest File Format tại đây

Đây là cấu trúc thư mục extension của mình

Cấu trúc thư mục của extension
Cấu trúc thư mục của extension

Bạn có thể sắp xếp các file, folder tùy ý làm sao @include đúng đường dẫn các file là được.

Như các bạn thấy ở phần browser_action :

  1. default_icon có giá trị là icon16.png, mình đã tạo sẵn 3 kích thước icon trong thư mục images để làm icon cho extension giờ mình trỏ đường dẫn tới thôi.
  2. default_popup có giá trị là popup.html, nên mình sẽ tạo một file có tên là popup.html vào thư mục page để tạo giao diện cho popup hiện lên khi chúng ta click vào extension.

HTML

Bây giờ chúng ta mở file popup.html và tạo cấu trúc các thẻ như một file html bình thường:

<!DOCTYPE html>
<html lang="en">

<head>
    <title></title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="../css/style.css" rel="stylesheet">
    <!-- Compiled and minified CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css">
</head>

<body>
    <div class="row">
        <div class="col s12 m8">
            <input id="tag" value="funny" />
        </div>
        <div class="col s12 m4">
            <a id="getGif" class="waves-effect waves-light btn-large">Get Image</a>
        </div>
        <p></p>
    </div>
    <div class="row">
        <div class="col s12 center">
            <div id="content">
            </div>
        </div>
    </div>
    <!-- Compiled and minified JavaScript -->
    <script src="../scripts/jquery-3.2.1.min.js"></script>
    <script src="../scripts/materialize.min.js"></script>
    <script src="../scripts/clipboard.min.js"></script>
    <script src="../scripts/popup.js"></script>
</body>

</html>

Ở extension này mình có sử dụng thêm thư viện jquery để hỗ trợ viết js, materializecss.com hỗ trợ về css – đây là một UI framework theo chuẩn Material Design khá là hay các bạn có thể tham khảo ở link trên, phần css materialize mình để vào link header luôn, còn js materialize mình download về và include vào vì js từ external link nó xử lý không được chuẩn cho lắm, ngoài ra mình sử dụng thêm library clipboard.js hỗ trợ copy text to clipboard, popup.js là phần mình viết js để xử lý get image và hiển thị trên extension.

JS

Tiếp tục sang phần js xử lý, để giphy.com random ảnh trả về cho chúng ta hiển thị thì bạn cần có api_key developer của trang này. Các bạn truy cập vào đây https://developers.giphy.com login và tạo một app để lấy api_key.

Sau khi đã có api_key, bạn thử truy cập vào trang sau https://api.giphy.com/v1/gifs/random?api_key=key_cua_ban&tag=funny&rating=G, rating bạn có thể để hoặc không tùy các bạn.

Kết quả trả về sẽ là 1 chuỗi json của ảnh gif được lấy theo tag là funny .

{
   "data":
   {
       "type": "gif",
       "id": "l0Exg7sYYOUPDeUiA",
       "url": "http://giphy.com/gifs/oscars-academy-awards-1997-l0Exg7sYYOUPDeUiA",
       "image_original_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/giphy.gif",
       "image_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/giphy.gif",
       "image_mp4_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/giphy.mp4",
       "image_frames": "19",
       "image_width": "480",
       "image_height": "359",
       "fixed_height_downsampled_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/200_d.gif",
       "fixed_height_downsampled_width": "267",
       "fixed_height_downsampled_height": "200",
       "fixed_width_downsampled_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/200w_d.gif",
       "fixed_width_downsampled_width": "200",
       "fixed_width_downsampled_height": "150",
       "fixed_height_small_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/100.gif",
       "fixed_height_small_still_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/100_s.gif",
       "fixed_height_small_width": "134",
       "fixed_height_small_height": "100",
       "fixed_width_small_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/100w.gif",
       "fixed_width_small_still_url": "https://media2.giphy.com/media/l0Exg7sYYOUPDeUiA/100w_s.gif",
       "fixed_width_small_width": "100",
       "fixed_width_small_height": "75",
       "username": "oscars",
       "caption": ""
   },
   "meta":
   {
       "status": 200,
       "msg": "OK",
       "response_id": "59c7a0f84a6c6252495993e1"
   }
}

Bây giờ chúng ta mở file popup.js lên viết js xử lý cho nó.

$(document).ready(function() {

    // this show preloader loading when getJson waiting result, support by Materialize 
    $(document).ajaxStart(function() {
        $('#content').html('<div class="preloader-wrapper big active"> <div class="spinner-layer spinner-blue"> <div class="circle-clipper left"> <div class="circle"></div> </div> <div class="gap-patch"> <div class="circle"></div> </div> <div class="circle-clipper right"> <div class="circle"></div> </div> </div> <div class="spinner-layer spinner-red"> <div class="circle-clipper left"> <div class="circle"></div> </div> <div class="gap-patch"> <div class="circle"></div> </div> <div class="circle-clipper right"> <div class="circle"></div> </div> </div> <div class="spinner-layer spinner-yellow"> <div class="circle-clipper left"> <div class="circle"></div> </div> <div class="gap-patch"> <div class="circle"></div> </div> <div class="circle-clipper right"> <div class="circle"></div> </div> </div> <div class="spinner-layer spinner-green"> <div class="circle-clipper left"> <div class="circle"></div> </div> <div class="gap-patch"> <div class="circle"></div> </div> <div class="circle-clipper right"> <div class="circle"></div> </div> </div> </div>');
    });

    $('#getGif').click(function(e) {
        e.preventDefault();
        // remove button copy image when click get image  continuously.
        $('#copyImage').remove();

        // Get value tag from input 
        let tag = $('#tag').val();
        // Link return random image   
        let url = 'https://api.giphy.com/v1/gifs/random?api_key=D2uR3vSJl9akcTQ1eRbjaiNbRR1m892O&tag=';

        // Because giphy return json object should we will use getJson
        /** 
         * @param url 
         * @param data  {tag}
         */
        $.getJSON(url, tag,
            function(json, textStatus, jqXHR) {
                // check json array length
                // if array length # 0 then show image
                // else show toast
                if (json.data.length != 0) {
                    showImage(json);
                } else {
                    Materialize.toast('No found image.', 3000, 'rounded');
                }
            }
        );
    });
    // Check status copy link image
    checkCopyLinkImage();
});

function checkCopyLinkImage() {
    var clipboard = new Clipboard('#copyImage');
    clipboard.on('success', function(e) {
        // console.log(e);
        // If copy success then remove button copy image and show toast.
        // remove button copy image.
        $('#copyImage').remove();
        // Show toast 'Copy successful image link!', support by Materialize
        Materialize.toast('Copy successful image link!', 3000, 'rounded');
    });
    clipboard.on('error', function(e) {
        // console.log(e);
        // If error then show toast
        // Show toast 'Copy fail image link!', support by Materialize
        Materialize.toast('Copy fail image link!', 3000, 'rounded');
    });
}

function showImage(json) {
    // Add image html to div content
    $('#content').html('<a href="' + json.data.url + '" target="_blank"><img class="responsive-img" src="' + json.data.image_original_url + '" alt="gif loading" title="' + json.datacaption + '"/></a>');
    // Add button copy after button get image 
    // This action click button copy image has clipboard.js handled.
    // Oly add data-clipboard-text="url_image" 
    $('#getGif').after(' <a id="copyImage" class="waves-effect waves-light btn-large" data-clipboard-text="' + json.data.image_original_url + '">Copy image</a>');
}

Tất cả những gì quan trong mình đã comment note khá rõ ràng trong file js, nếu bạn có thắc mắc gì xin vui lòng để lại comment bên dưới.

Đóng gói tiện ích

Sau khi đã code xong xuôi rồi giờ là lúc hưởng thụ thành quả thôi.

Trên Chrome bạn gõ vào đường dẫn chrome://extensions/ hoặc truy cập tiện ích mở rộng từ setting

Cách thứ nhất để cài Extension cho Chrome là kéo thả thư mục của extension vào

Cài đặt Extension
Cài đặt Extension

Cách thứ 2 là gõ vào đường dẫn chrome://extensions/ hoặc truy cập tiện ích mở rộng từ setting, ở đây mình đang để ngôn ngữ hiển thị của chrome là tiếng việt nhé.

Click vào chế độ nhà phát triển -> Tải tiện ích đã bung -> Chọn folder extension -> OK xong. 😀

Cài đặt Extension
Cài đặt Extension

Để upload extension của bạn lên webstore, bạn có thể làm theo hướng dẫn này https://developer.chrome.com/webstore/publish

Project on Github: https://github.com/trongcong/Chrome-Extension-Giphy-Loader

Chúc các bạn thành công! Goodluck! ???

Oh My Zsh: Nâng cao trải nghiệm terminal với giao diện đẹp và các plugin tăng hiệu suất! Git cherry-pick là gì? Cách sử dụng và ví dụ Git Rebase: Gộp nhiều commit thành một để tối ưu hóa lịch sử commit 11 tính năng JavaScript mới tuyệt vời trong ES13 (ES2022) CSS diệu kỳ: Các thuộc tính CSS mà bạn có thể chưa biết Auto deploy projects với GitHub Actions – sử dụng ssh-action WordPress Gutenberg Block Server Side Render Add, Upload image trong Gutenberg Block Development Tạo Block Controls – Block Toolbar và Settings Sidebar trong WordPress Gutenberg Làm quen với các components thường dùng khi tạo Gutenberg Block

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.