Creating Extensions

Extensions are collections of javascript files and stylesheets that can expand Static Ultra's capabilities without messing with the core code. For example, this site provides extensions for Disqus comments and GoatCounter analytics.

Extensions are easy to download and install on your site, and the idea is that people can make and share them.

You could make extensions for all kinds of stuff. Maybe a photo gallery widget? Implementing Twitter stuff? Parsing markdown/BBCode blocks in your site? Those are just a few ideas. Can you think of some better ones? WELL?

Anywho, if you have some JavaScript experience, making extensions is really easy! Let's see... examples... examples. How about an extension which gives the user some information about their session on your site, e.g. when their session started, how many pages they have visited, and how many times they've switched themes.

First, go to your site's root folder, and create a folder called su-extensions if it doesn't exist.

Inside the su-extensions folder, create a folder called session-info. This will be the name of your extension.

Inside the session-info folder, create a new file called extension.js. Open up extension.js for editing, and paste in the following code:

"use strict"; function SUExtension_SessionInfo() { // Called when your site loads this.onSiteLoad = function() { console.log( "SessionInfo.onSiteLoad()" ); } // Called when a theme has loaded this.onThemeLoad = function() { console.log( "SessionInfo.onThemeLoad()" ); } // Called when a page has loaded this.onPageLoad = function() { console.log( "SessionInfo.onPageLoad()" ); } // Called when a page has unloaded, before new page inserted this.onPageUnload = function() { console.log( "SessionInfo.onPageUnload()" ); } // Called when a theme has unloaded, before new theme inserted this.onThemeUnload = function() { console.log( "SessionInfo.onThemeUnload()" ); } // Strict Object.seal( this ); }

Alright! As you can see we've made a class called SUExtension_SessionInfo. It's important that your class has the name SUExtension_XXX or Static Ultra won't know wot not do to with it olroyt?

Before we start making it work, let's get it loading into your site.

Open up your su-config.js for editing, and look for the line this.EXTENSIONS = []. (If you happen to be on SU 1.0.0, the line won't exist so put it in now. It can go anywhere but I recommend putting it after the line this.THEME_SWITCHING_ENABLE = true).

Now, to make the extension load, adjust the this.EXTENSIONS line to the following:

this.EXTENSIONS = [ // SessionInfo { "id": "session-info", "classID": "SessionInfo", "files": [ "extension.js" ] }, ];

Now, visit your site and press F12. This will bring up the developer console. Press Ctrl+F5. You should now see in your console:

SessionInfo.onSiteLoad()
SessionInfo.onThemeLoad()
SessionInfo.onPageLoad()

Congrats! Your extension is loading and you're ready to start making it do stuff.

So, go back to editing extension.js, and replace the code with the following. Don't be alarmed! It's pretty straight forward, have a read through to see how it works. I'll also explain it below.

"use strict"; function SUExtension_SessionInfo() { var sessionStartDate = ""; var sessionStartTime = ""; var numPageVisits = 0; var numThemeSwitches = 0; // Called when your site loads (session start) this.onSiteLoad = function() { // Get session start date and time in a readable format var dateObj = new Date(); var dayOfWeek = dayNumToStr( dateObj.getDay() ); // Use helper function to get readable day of week e.g. (Monday) var dayOfMonth = dateObj.getDate(); var month = monthNumToStr( dateObj.getMonth() ); var year = dateObj.getFullYear(); var hour = dateObj.getHours(); var minutes = dateObj.getMinutes(); sessionStartDate = dayOfWeek + ", " + dayOfMonth + " " + month + " " + year; sessionStartTime = hour + ":" + minutes; } // Called when a theme has loaded this.onThemeLoad = function() { // Increase theme switch count numThemeSwitches++; } // Called when a page has loaded this.onPageLoad = function() { // Increase page visit count numPageVisits++; // Look for <div class=".session-info"></div> var sessionInfoDiv = document.querySelector( ".session-info" ); // If not found do nothing if( sessionInfoDiv == null ) return; // Update the div with the infos sessionInfoDiv.innerHTML = ` <div class="session-info-panel"> <div>Your session started on: ` + sessionStartDate + ` at ` + sessionStartTime + `</div> <div>You have visited <span class="session-info-num-page-visits">` + numPageVisits + `</span> pages.</div> <div>You have switched themes <span class="session-info-num-theme-switches">` + numThemeSwitches + `</span> times.</div> </div> `; } // Called when a page has unloaded, before new page inserted this.onPageUnload = function() { } // Called when a theme has unloaded, before new theme inserted this.onThemeUnload = function() { } // Convert from 0-6 to Monday-Sunday function dayNumToStr( dayNum ) { if( dayNum == 0 ) return "Sunday"; if( dayNum == 1 ) return "Monday"; if( dayNum == 2 ) return "Tuesday"; if( dayNum == 3 ) return "Wednesday"; if( dayNum == 4 ) return "Thursday"; if( dayNum == 5 ) return "Friday"; return "Saturday"; } // Convert from 0-11 to January-December function monthNumToStr( monthNum ) { if( monthNum == 0 ) return "January"; if( monthNum == 1 ) return "February"; if( monthNum == 2 ) return "March"; if( monthNum == 3 ) return "April"; if( monthNum == 4 ) return "May"; if( monthNum == 5 ) return "June"; if( monthNum == 6 ) return "July"; if( monthNum == 7 ) return "August"; if( monthNum == 8 ) return "September"; if( monthNum == 9 ) return "October"; if( monthNum == 10 ) return "November"; return "December"; } // Strict Object.seal( this ); }

So, we've made a few class variables. sessionStartDate and sessionStartTime are for storing when your visitor first visited the site. numPageVisits and numThemeSwitches store the number of page visits and theme switches.

We've updated the onSiteLoad() function so that it works out a readable version of the current date and time when they visit the site (which is when onSiteLoad is called), and stores them in our variables. To do this is makes use of the dayNumToStr and monthNumToStr helper functions which we added to the bottom of the file.

In the onThemeLoad() function, we increase the number of theme switches.

In onPageLoad(), we update the page visit count variable. Then we look for a div with class .session-info. If it doesn't exist, we do nothing! If it DOES exist, we fill it out with all the information we have stored in our variables.

Visit your site and press Ctrl+F5. Guess what? Nothing happens! :D That's because we need to put the following in our page or theme.

<div class="session-info">&nbsp;</div>

So, go ahead and put that in one of your pages. Press Ctrl+F5, and you should see something like the following (the following is just an example and does not have the right stuff in it):

Your session started on: Saturday, 14 April 2023 at 11:30
You have visited 1 pages.
You have switched themes 1 times.

Yuck. Sure, it works, but it doesn't look very nice does it? Well, let's do something about that, by adding a stylesheet to our extension.

Note: You may be wondering why it says you've only visited 1 page. This is because you refreshed. If you visit pages without refreshing, the page count will be correct. You could improve upon this using JavaScript's sessionStorage, but that is beyond the scope (and point) if this tutorial.

So, stylesheet. Go to your su-extensions/session-info/ folder, and create a new file called extension.css.

Open it up and paste in the following:

.session-info-panel { border:solid 2px orange; border-radius:8px; padding:8px; background-image: linear-gradient(to bottom, #4ad748, #00eac6, #41f1ff, #ccf3ff, #ffffff); } .session-info-num-page-visits { color:green; font-weight:bold; } .session-info-num-theme-switches { color:blue; font-weight:bold; }

Now, go to su-config.js, and tell it about the file you just added:

// SessionInfo { "id": "session-info", "classID": "SessionInfo", "files": [ "extension.css", "extension.js" ] }

Go back to your site, and refresh, you should see something like this (this is a real one, not an example xD):

 

Yuck. It's still horrible. But hey it demonstrates the point right?

You can have as many stylesheets and script files in your extension as you want, for example, let's say we wanted to move the helper functions to another class.

Go to the su-extensions/session-info folder, and create a new file called helpers.js.

Open up the file, and paste in the following:

"use strict"; function SessionInfo_Helpers() { // Convert from 0-6 to Monday-Sunday this.dayNumToStr = function( dayNum ) { if( dayNum == 0 ) return "Sunday"; if( dayNum == 1 ) return "Monday"; if( dayNum == 2 ) return "Tuesday"; if( dayNum == 3 ) return "Wednesday"; if( dayNum == 4 ) return "Thursday"; if( dayNum == 5 ) return "Friday"; return "Saturday"; } // Convert from 0-11 to January-December this.monthNumToStr = function( monthNum ) { if( monthNum == 0 ) return "January"; if( monthNum == 1 ) return "February"; if( monthNum == 2 ) return "March"; if( monthNum == 3 ) return "April"; if( monthNum == 4 ) return "May"; if( monthNum == 5 ) return "June"; if( monthNum == 6 ) return "July"; if( monthNum == 7 ) return "August"; if( monthNum == 8 ) return "September"; if( monthNum == 9 ) return "October"; if( monthNum == 10 ) return "November"; return "December"; } // Strict Object.seal( this ); }

Static Ultra doesn't give a hoot what you call this class, I just called it SessionInfo_Helpers for tidiness.

Open up extension.js, and adjust it as follows:

"use strict"; function SUExtension_SessionInfo() { var helpers = null; var sessionStartDate = ""; var sessionStartTime = ""; var numPageVisits = 0; var numThemeSwitches = 0; // Called when your site loads (session start) this.onSiteLoad = function() { helpers = new SessionInfo_Helpers(); // Get session start date and time in a readable format var dateObj = new Date(); var dayOfWeek = helpers.dayNumToStr( dateObj.getDay() ); // Use helper function to get readable day of week e.g. (Monday) var dayOfMonth = dateObj.getDate(); var month = helpers.monthNumToStr( dateObj.getMonth() ); var year = dateObj.getFullYear(); var hour = dateObj.getHours(); var minutes = dateObj.getMinutes(); sessionStartDate = dayOfWeek + ", " + dayOfMonth + " " + month + " " + year; sessionStartTime = hour + ":" + minutes; } // Called when a theme has loaded this.onThemeLoad = function() { // Increase theme switch count numThemeSwitches++; } // Called when a page has loaded this.onPageLoad = function() { // Increase page visit count numPageVisits++; // Look for <div class=".session-info"></div> var sessionInfoDiv = document.querySelector( ".session-info" ); // If not found do nothing if( sessionInfoDiv == null ) return; // Update the div with the infos sessionInfoDiv.innerHTML = ` <div class="session-info-panel"> <div>Your session started on: ` + sessionStartDate + ` at ` + sessionStartTime + `</div> <div>You have visited <span class="session-info-num-page-visits">` + numPageVisits + `</span> pages.</div> <div>You have switched themes <span class="session-info-num-theme-switches">` + numThemeSwitches + `</span> times.</div> </div> `; } // Called when a page has unloaded, before new page inserted this.onPageUnload = function() { } // Called when a theme has unloaded, before new theme inserted this.onThemeUnload = function() { } // Strict Object.seal( this ); }

As you can see, we've removed the helpers, since we're now using the helpers object version instead.

One more step! Need to update su-config.js to have the new file we just made.

// SessionInfo { "id": "session-info", "classID": "SessionInfo", "files": [ "extension.css", "helpers.js", "extension.js" ] }

Visit your site, Ctrl+F5, nothing changes. But hey you've got more organised code!

Sharing your extension

So, you've created your extension and it's working great. But what if you want others to be able to use it?

Well, all you do is zip up the extension folder, and tell people to extract it, put it in their own su-extensions folder, and to update their su-config as above.

End

This concludes the creating extensions tutorial. I hope you found it useful!