PART 2: Building the extension
Getting started
This is the second part of the tutorial, If you missed the first part of this tutorial, you can find it here.
Open listed files using your preferred IDE or text editor:
- global.hml
- popover.html
- listner.js
The End Script
The main goal of using an End Script,because it has access to the DOM of the web page. This is the only place where we can put ourJS code with the ability to addthe event listener on the visited page elements.
listener.js souce code
function clickHandler(o,recursive) { var e=(recursive)?o:o.target; if ($(e).is('a')) { /* clicked element is a link so send a message with link information to global file (calls handleMessage function) */ safari.self.tab.dispatchMessage("link", $(e).get(0).href); } else { /* if the clicked element is not a link so we need to go up to the parent element recursively util a link tag is found. */ var parent = $(e).parents("a").get(0); if(parent) { clickHandler(parent,true); } } } /* bind clickHandler function for each existing element of the document. clickHandler will trigger when user click on a element. */ $(document).on("click",clickHandler);
As you can see in the source code above in line 28, the advantage of using JQuery.on() that the attached click Event handler clickHandler() will work for both current and FUTURE elements (like a new element created by a script). The purpose is that when the user clicks on an element clickHandler() will be executed and the clicked element (the object) itself will be passed as parameter to this function. Inside this function we check the element type. If it is a link or an element wrapped by a link tag <a> we dispatch a message containing link information to the Global Page.
The Global Page
global.html source code:
<!DOCTYPE html> <html> <head> <script type="text/javascript" charset="utf-8"> const gui = safari.extension.popovers[0].contentWindow //Create the popover instance function handleMessage(msg){ if (msg.name == "link"){ //exectue addLink() inside popover gui.addLink(msg.message); } } //creating the event listener safari.application.addEventListener("message",handleMessage, false); </script> </head> <body></body> </html>
As show above in the Global Page source code, the event listener in line 13 is executed once Safari launches or when enabling the extension, it tells handleMessage() to catch incoming messages from external scripts. When dispatchMessage() is executed inside “listener.js”, the message will be immediately cached by handleMessage() from the global page. Inside this function the message type is checked then addLink() from “popover.html” is called with passing the link URL as parameter. addLink() will update the container from the Popover by adding a new row. You should know that you can’t update Popover interface from the global page because it hasn’t got access to Popover DOM.
The Popover
The popover.html is the user interface. It’s based on usual Web scripting technologies HTML, CSS and JavaScript. As mentioned earlier we placed addLink() inside this script file because this is the only place we can access the Popover DOM.
popover.html source code:
<!DOCTYPE html> <html> <head> <script type="text/javascript" charset="utf-8" src="jquery-1.7.min.js"></script> <style type="text/css"> body { color: #333; font-family: tahoma; font-size: 10px; background: #F7F7F7; } h1 { text-align: center;; font-size: 12px; color: #990000; } #container { outline: 1px solid #AAA; padding: 4px; background: #FFF; height: 350px; overflow-y: auto; } .entry { padding-top: 6px; } .link { cursor: hand; cursor: pointer; color: #0099CC; } .link:hover { color: blue; } .time { padding-right: 4px; } </style> <script type="text/javascript" charset="utf-8"> function addLink(link) { $("#start").after('<div class="entry"><span class="time">'+getDateTime()+'</span><span class="link" onclick=\'openLink("'+link+'")\'>'+getShortString(link,34)+'</span></div>'); } function getShortString( str, limit ) { if (str.length > limit) { return str.substring(0,limit)+"..."; } else { return str; } } function openLink(link) { safari.application.activeBrowserWindow.openTab().url=link; } function getDateTime() { var currentdate = new Date(); var datetime = ('0' +currentdate.getDate()).slice(-2) + "/" + ('0' +(currentdate.getMonth()+1)).slice(-2) + "/" + currentdate.getFullYear() + " " + ('0' +currentdate.getHours()).slice(-2) + ":" + ('0' +currentdate.getMinutes()).slice(-2); return datetime; } </script> </head> <h1>Visited Links Logger</h1> <body> <div id="container"> <span id="start" style="display:none"/> </div> </body> </html>
The picture below summarizes the above text.
Testing Extension Package
The development of Visited Links Logger Safari extension has come to the end and it’s now time to test it. Ready? So, go to the Extension Builder then click on Reload button which will update our extension by new the modifications we made.
Now everything should be fine, try to visit a few web pages and click on the links inside, you will get a result like in the picture below.
Building Extension Package
At this point we are still in the development stage and we haven’t made a finished extension yet, the extension is stored as a folder that contains some source files and an icon, for the moment it can’t be delivered to any end-users. All we need to do next is to generate a compact package. Once again the Extension Builder makes this task very easy to do by a single click on the Build Package button (see the picture below) then choose where you want to save your package.
As a result, you should have a new package named: “VistedLinksLogger.safariextz”, it can be installed by opening the file or dragging it to Safari. You can also publish this extension in the Apple extension gallery.
Here is the project (zipped) : VisitedLinksLogger.safariextension.zip
I hope this tutorial was very helpful. If you need more help, please don’t hesitate to contact me or leave a comment and I will try to reply ASAP. To end off, I would like to thank Paola Pereira for the English review.
Weiter says:
Please let me know if you’re looking for a writer for your weblog.
You have some really great articles and I believe I would be a good asset.
If you ever want to take some of the load off, I’d absolutely love to write some articles for your blog in exchange for a link back to mine.
Please blast me an e-mail if interested.
Kudos!
Hamza says:
Good job really!
You helped me a lot.
Stormy says:
Hello, Neat post. There is a problem with your web site in web explorer, might check
this? IE nonetheless is the marketplace chief and a big section of folks will leave out your excellent writing due to this problem.
Stormy
harrisonburgtech.com says:
Ι like it when folks get together and share thoughts.
Great website, continue the good work!
Perverse Creampie says:
Je me permets de publier ce com simplement pour congratuler l’administrateur
Jacqueline says:
I see a lot of interesting posts on your website.
You have to spend a lot of time writing, i know how to save you
a lot of time, there is a tool that creates unique,
google friendly articles in couple of seconds, just type in google – k2 unlimited content
Nadia says:
I read a lot of interesting articles here. Probably you spend a lot of time writing, i know how to save you a lot of
work, there is an online tool that creates unique, google friendly posts in minutes, just search in google
– laranitas free content source
micho says:
Very good article!
Is it possible to use builtin safari functions like print_2_pdf?
I want an extension to store the site as a pdf
see this site says:
This simple sensor gadget, which is iin regards to the measurement of a pen, indicates the presence of
electrical voltage.
terapi ozon miss V says:
Great site you have here.. It’s difficult to find high-quality
writing like yours these days. I honestly appreciate people like you!
Take care!!
Trent says:
Dated, but still helpful. Thanks!
Pawan says:
Hello Sir, i want to port my extension written in chrome to safari browser on macos how can i do it because i am not able to find any relatable tutorials for it even on apple developers site can you help in any way?