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 .
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 ??
Đù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:
- 50+ thuộc tính thú vị trong CSS
- Giải pháp search nhanh như điện xẹt cho trang web WordPress với Algolia
- Tạo Blog đơn giản với Nuxt JS và WordPress API
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:
- manifest_version: là version chrome extension bạn sử dụng (hiện nay là version 2).
- name: Đây là tên của extension trên Chrome.
- version: Phiên bản của extenssion.
- description: Mô tả cho extension.
- icons: Icons đại diện cho extension, app, hoặc theme, bạn nên có 3 kích cỡ 16px, 48px, 128px.
- browser_action: Dùng để tùy chỉnh icon, popup, tooltip, …
- 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.
- 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
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 :
- 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.
- 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á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. 😀
Để 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! ???