To write an extension for google chrome is easy. But when writing the first expansion, questions may arise (and arise). Most of the manuals for writing the first extension are designed to use the manifest of the first version, whose support will cease in the near future.
This article will cover:
- How to make a manifest v.2
- How to work with remote resources
- How to work with cookies
- How to work with local storage
- How to work with notifications
Introduction
By the end of the article we will have an organizer extension in which there will be a field for adding a new task, as well as a list of tasks for the current day. Denote all the requirements for the organizer:
- Must have a field to add an event (date, time, event)
- Must display all tasks for the current day, sorted by time
- All past events should display strikethrough
- Must have a field to enter the time for how much to show the notification, as well as the checkbox allowing and prohibiting the display of notifications
- A specified time before the event should display a notification about the upcoming event.
Manifesto
Let's start creating an extension from the very beginning, that is, from the manifest. The manifest is the same file in which all the extension parameters are written. Name, description, version, permission to access sites, permission to use cookies, notifications, local storage. In general, the manifesto is the brain of expansion. Create file manifest.json. The manifest is the only file that should have a predefined name; all other files can be named as you please. There are three required fields in this file:
manifest.json{ “name”: “Organizer extension”,
')
There are a couple of rules here:
- The manifest version must be integer, that is, must be written as 2, not “2”.
- The extension version must be string, but contain only numbers and periods, that is, “1.0” is good, and 1.0 and “0.9 beta” is bad.
With the required fields - everything, let's move on to creating a pop-up extension window. In order to open a window by clicking on the icon, you need to add the “browser_action” field to the manifest
manifest.json { … "browser_action": { "default_title": "Open organizer",
Now create a popup window. This is a regular html page, which can be of any size and color, no tricks. Name the file “popup.html”. Create this file is not enough - it must be specified in the manifest. So we did: “default_popup”: “popup.html”.
popup.html <!DOCTYPE html> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <div>It works!</div> </body> </html>
Adding an extension to the browser
Now it's time to test the performance of our extension. To do this, upload the extension to the browser. Open in the chrome menu extensions. Put the bird on “Developer mode”.

After that there will be three buttons. Click “Load unpacked extension ...”. Select the folder with the extension files. After this, our extension will appear. If everything is correct, then by clicking on the icon - the window will pop up:

Connecting scripts
Now you can proceed to the interesting. Connect two javascript files. The first is popup.js, the second is jquery. There will be no problem with the first one, but we will connect jquery not local, but remote, taken at
ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js . Problems will arise from the fact that the default extension does not have access to third-party resources. To access, you must specify it in the manifest. Access to something is indicated in the “permissions” field. Also, for remote scripts and css, you must specify the available remote resources.
manifest.json { … "permissions": [ "https://ajax.googleapis.com/*" ], "content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'" }
Now connect these scripts to popup.html
popup.html <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <script src="popup.js"></script>
Storage
With the help of storage in chrome, you can store user data. And it is in the storage that our extension will store future events. There are two reasons for this. First, the data stored in storage can be synchronized if logged in to the browser. And secondly, the data can be stored not only as strings, as in cookies, but in any form, that is, you can store arrays and objects. To make it work, let's open access to storage in the manifest.
manifest.json { ... "permissions": [ … "storage" ] ... }
Now we will remake the popup window. In the pop-up window there will be a field with today's date, three inputs for the date, time and description of the new event, a button for adding a new event, as well as a list of all events for today.
popup.html <div id="container"> <div id="today_date">Date</div> <table class="table"> <tr> <td></td> <td></td> <td></td> </tr> <tr> <td><input type="text" id="new_date" value="" class="input_date" /></td> <td><input type="text" id="new_time" value="" class="input_date" /></td> <td><input type="text" id="new_task" value="" class="input_task" /></td> </tr> </table> <ul></ul> </div>
And immediately add the date display in the #today_date block.
popup.js $(function(){ var today = new Date(); $("#today_date").html(today.getDate()+"."+(parseInt(today.getMonth())+1)+"." + today.getFullYear()); }
It should look like this:

So, when you click on the “+” button, we should add an event. At the beginning of the file we will declare a global variable storage - an object for working with storage, as well as a global array of tasks for storing events.
popup.js var storage = chrome.storage.sync; var tasks = new Array(); $(function(){ … $("#add_task").click(function(){ var new_task = new Object(); new_task.date = validateField($("#new_date").val(), "date"); new_task.time = validateField($("#new_time").val(), "time"); new_task.task = $("#new_task").val(); if(!new_task.task || !new_task.date || !new_task.task){ return false; } tasks[tasks.length] = new_task; storage.set({ tasks:tasks }); }); });
The validation function checks that the date is recorded in the dmyyyy format, and the time in the hh: mm format, and also that the description of the event contains at least three characters.
popup.js var validateField = function(val, type){ if(type == "date"){ var date = val.split("."); var year = new Date(); year = year.getFullYear(); if(date.length == 3 && parseInt(date[0]) == date[0] && date[0] <= 31 && parseInt(date[1]) == date[1] && date[1] <= 12 && parseInt(date[2]) == date[2] && date[2] >= year){return val;} } else if(type == "time"){ var time = val.split(":"); if(time.length == 2 && parseInt(time[0]) == time[0] && time[0] < 24 && parseInt(time[1]) == time[1] && time[1] < 60){return val;} } else if(type == "task" && type.length >= 3){ return val; } return null; }
With the addition of understood, proceed to receive the events for today. To do this, you need to get all the events from the database, select only today's events from all of them and sort them by time in ascending order.
popup.js $(function(){ … var now_hours = today.getHours() < 10 ? "0" + today.getHours() : today.getHours(); var now_minutes = today.getMinutes() < 10 ? "0" + today.getMinutes() : today.getMinutes(); var now_time = now_hours + "" + now_minutes; storage.get("tasks",function(items){ if(items.tasks){ tasks = items.tasks; var today_tasks = getTodayTasks(tasks); if(today_tasks.length >0){ for(var i in today_tasks){ var this_time = today_tasks[i].time.replace(":", ""); var add = this_time > now_time ? "" : ' class="done"'; var add_html = '<li'+add+'><strong>'+today_tasks[i].time+'</strong> '+today_tasks[i].task+'</li>'; $("ul").append(add_html); } } } }); … });
The getTodayTasks () function returns from the general list only events with today's date.
popup.js var getTodayTasks = function(tasks){ var today_tasks = new Array(); var today = new Date(); var today_date = today.getDate()+"."+(today.getMonth() + 1 )+ "." + today.getFullYear(); for(var i in tasks){ if(tasks[i].date == today_date){ today_tasks[today_tasks.length] = tasks[i]; } } if(today_tasks.length > 0){ today_tasks = sortTasks(today_tasks); } return today_tasks; }
The sortTasks () function sorts events by time.
popup.js var sortTasks = function(tasks){ if(tasks.length > 0){ var swapped = true; while (swapped) { swapped = false; for (var i=0; i < tasks.length-1; i++) { var this_time = tasks[i].time.replace(":", ""); var next_time = tasks[i+1].time.replace(":", ""); if (this_time > next_time) { var temp = tasks[i]; tasks[i] = tasks[i+1]; tasks[i+1] = temp; swapped = true; } } } } return tasks; }
Notifications
It's time to customize the display of notifications on the screen. Add a special checkbox to the pop-up window. If this checkbox is checked, notifications will be shown, if not checked, they will not. Also add a text input. The number in this route will show how long before the event the notification will be displayed. That is, if we have an event scheduled for 19:00, in this text input there will be 5, then at 18:55 a notification will appear. Add to popup.html code with these inputs.
popup.html <div> <input type="checkbox" id="show_notifications" checked="checked" /> <input type="text" id="when_to_notify" class="input_date" value="" /> </div>

Now let's see how this will work. When you click on the checkbox, its checked attribute will be checked, the attribute value will be recorded in the cookie “show_notifications”. Let's move on to text input. By changing its value, the new value will be validated, if it is an integer and not more than 120, we write the new value in the “when_to_notify” cookie.
But in order for it to work, we need to open access to cookies. To do this, go to manifest.json and add to “permissions”
manifest.json { ... "permissions": [ … “cookies” ] ... }
Now you can proceed to the script. Go to popup.js. To begin with we will establish initial values ​​in inputa. By default, the checkbox is unchecked, that is, notifications are not shown, and the time is 0. When you click on the checkbox, the “show_notifications” cookie will change. When changing the value in the text field, the value of the “when_to_notify” cookie will change.
popup.js $(function(){ setCheckbox(); setWhenToNotify(getCookie("when_to_notify")); ... $("#show_notifications").click(function(){ setCookie("show_notifications", document.getElementById("show_notifications").checked); }); $("#when_to_notify").change(function(){ setWhenToNotify($(this).val()); }); });
Consider more features. Let's start with the functions of working with cookies. In this case, ready-made functions were taken from w3schools.com.
popup.js var setCookie = function(c_name,value,exdays){ var exdate=new Date(); exdate.setDate(exdate.getDate() + exdays); var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString()); document.cookie=c_name + "=" + c_value; } var getCookie = function(c_name){ . var i,x,y,ARRcookies=document.cookie.split(";"); for (i=0;i<ARRcookies.length;i++){ x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("=")); y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1); x=x.replace(/^\s+|\s+$/g,""); if (x==c_name){ return unescape(y); } } }
We will deal with the setCheckbox () function. It receives the cookie “show_notifications” and checks if the resulting value is “true” (text, yes), then the checked parameter of the check box is true, otherwise false.
popup.js var setCheckbox = function(){ var val = getCookie("show_notifications") document.getElementById('show_notifications').checked = ((val == "true") ? true : false); }
Now consider setWhenToNotify (). It takes a new timer value. If this value is integer and not more than 120 minutes, then in the “when_to_notify” cookie the new value is set. If the variable did not pass this validation, then the previous value from the “when_to_notify” cookie is returned to the input.
popup.js var setWhenToNotify = function(val){ var last_val = getCookie("when_to_notify"); last_val = last_val != "undefined"? last_val: 0; val = (parseInt(val)==val && val <=120) ? val : last_val; setCookie("when_to_notify", val); $("#when_to_notify").val(val); }
Let's go to the notifications themselves. To do this, open access to notifications and connect background background.js. It is necessary to include the background file, since if notifications are called from popup.js, then notifications will appear only if a pop-up window is open.
manifest.json { ... "permissions": [ … "notifications" ], "background": { "scripts": ["background.js"] }, "web_accessible_resources": ["icon_small.png"], ... }
The last line gives access to the deleted file. The fact is that the image that is displayed in the notification must be available to the extension remotely. In this case, the file is local, but access is still necessary. Now we will take on background.js. We declare a storage variable and an empty tasks array. Then once a minute, the script will receive a list of today's events and receive from them a list of tasks that should occur after a specified time. After that, a notification will be displayed for each such task.
background.js var storage = chrome.storage.sync; var tasks = new Array(); setInterval(function() { storage.get("tasks",function(items){ if(items.tasks && getCookie("show_notifications") == "true"){ tasks = getTodayTasks(items.tasks); if(window.webkitNotifications){ var texts = getNextTask(tasks); for(var i in texts){ show(texts[i]); } } } }); }, 60000);
The getTodayTasks () and getCookie () functions are taken from popup.js. So let's start parsing with the getNextTask () function. The function compares the current time and the event time, if it is equal to the value stored in the “when_to_notify” cookie, then a string from the event time and its description is added to the next array. After checking all the events, it returns the array next.
background.js var getNextTask = function(tasks){ var now = new Date(); now = now.getTime(); var next = new Array(); for(var i in tasks){ var date = tasks[i].date.split("."); var time = tasks[i].time.split(":"); var task_date = new Date(parseInt(date[2]), parseInt(date[1]-1), parseInt(date[0]), parseInt(time[0]), parseInt(time[1]), 0, 0); task_date = task_date.getTime(); var delta = Math.round((task_date-now)/60000); if(delta == getCookie("when_to_notify")){ next[next.length] = tasks[i].time + " - " + tasks[i].task; } } return next; }
The show () function displays a notification with the specified text.
background.js var show = function(text) { var notification = window.webkitNotifications.createNotification('icon_small.png',' ', text); notification.show(); }
The result of this script will be the following notification:

Afterword
As promised, at the end of the article we have a ready-made organizer extension for Google Chrome.
Now add the extension to the Chrome Web Store. It is necessary to load the extension packed into .zip-archive. First, go to the Web Store. To do this, go to the chrome tab “Applications” and click “Web Strore”

Now go to the menu. To do this, click the hex and open the “Developer dashboard”

Click the large “Add new item” button. After that, you will need to select a zip-archive with the extension click “upload”

Next you need to fill out a small form with a description of the extension. Now there is a choice to either save the extension to Chernovil or publish Just to publish it will not work because registration in the Web Store costs $ 5. Registration fees must be paid once per account, not for each extension. After payment there is a possibility to publish the extension, but even here we must be prepared for the fact that it will be validated for several days.
useful links
Description of the manifest fields:
developer.chrome.com/trunk/extensions/manifest.htmlWorking with storage:
developer.chrome.com/trunk/extensions/storage.htmlNotification information:
developer.chrome.com/extensions/notifications.htmlExpansion sources:
github.com/bozheville/orginaizer_extension