Implemented loading custom CSS and templates, implemented google analytics

This commit is contained in:
Mikko Ahlroth 2015-01-18 23:54:52 +02:00
parent 9fb8eada9f
commit ae5d23bd2c
11 changed files with 159 additions and 13 deletions

View file

@ -1,6 +1,6 @@
{
"name": "laine",
"version": "0.0.0",
"version": "0.1.0",
"private": true,
"dependencies": {
"components-bootstrap": "~3.1.1",

View file

@ -38,7 +38,8 @@ var requireJsRuntimeConfig = vm.runInNewContext(fs.readFileSync('src/app/require
'components/year-page/year-page',
'components/month-page/month-page',
'components/post-page/post-page',
'components/config-service/config-service'
'components/config-service/config-service',
'components/template-service/template-service'
],
insertRequire: ['app/startup'],
bundles: {

View file

@ -1,4 +1,12 @@
define(["knockout", "crossroads", "hasher", "./routes"], function(ko, crossroads, hasher, routes) {
define(
[
"knockout",
"crossroads",
"hasher",
"./routes",
"../components/config-service/config-service",
"../components/ga-service/ga-service"
], function(ko, crossroads, hasher, routes, configService, gaService) {
// This module configures crossroads.js, a routing library. If you prefer, you
// can use any other routing library (or none at all) as Knockout is designed to
@ -14,6 +22,8 @@ define(["knockout", "crossroads", "hasher", "./routes"], function(ko, crossroads
function Router(config) {
var currentRoute = this.currentRoute = ko.observable({});
this.crossroads = crossroads;
this.hasher = hasher;
ko.utils.arrayForEach(config.routes, function(route) {
var addedRoute = crossroads.addRoute(route.url, function(requestParams) {
@ -29,7 +39,15 @@ define(["knockout", "crossroads", "hasher", "./routes"], function(ko, crossroads
}
function activateCrossroads() {
function parseHash(newHash, oldHash) { crossroads.parse(newHash); }
function parseHash(newHash, oldHash) {
crossroads.parse(newHash);
// Send google analytics page event if it's enabled
if (configService.useGa) {
gaService.sendPageEvent();
}
}
crossroads.normalizeFn = crossroads.NORM_AS_OBJECT;
hasher.prependHash = '!';
hasher.initialized.add(parseHash);

View file

@ -61,7 +61,3 @@ define([], function() {
}
];
});

View file

@ -32,6 +32,10 @@ define(['jquery', 'knockout', './router', 'marked', 'bootstrap', 'knockout-proje
ko.components.register('config-service', { require: 'components/config-service/config-service' });
ko.components.register('template-service', { require: 'components/template-service/template-service' });
ko.components.register('ga-service', { require: 'components/ga-service/ga-service' });
// [Scaffolded component registrations will be inserted here. To retain this feature, don't remove this comment.]
// Set Markdown parser options

View file

@ -1,5 +1,5 @@
define(['knockout', '../../app/routes', '../../app/router', 'hasher'],
function(ko, routes, router, hasher) {
define(['knockout'],
function(ko) {
function ConfigService() {
var self = this;
@ -9,6 +9,18 @@ define(['knockout', '../../app/routes', '../../app/router', 'hasher'],
document.title = self.blogName;
self.baseTitle = self.blogName;
// Load custom CSS if specified
if (self.customCss) {
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.id = 'laine-custom-css';
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = self.customCss;
link.media = 'all';
head.appendChild(link);
}
}
// This runs when the component is torn down. Put here any logic necessary to clean up,

View file

@ -0,0 +1,34 @@
define(
[
'knockout',
'../config-service/config-service'
], function(ko, configService) {
function GaService() {
var self = this;
// The GA object that can be used in other components
self.ga = null;
if (configService.useGa) {
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', configService.webPropertyID, 'auto');
self.ga = ga;
}
self.sendPageEvent = function() {
self.ga('send', 'pageview');
};
}
// This runs when the component is torn down. Put here any logic necessary to clean up,
// for example cancelling setTimeouts or disposing Knockout subscriptions/computeds.
GaService.prototype.dispose = function() { };
return new GaService();
});

View file

@ -1,4 +1,10 @@
define(['knockout', '../db/db'], function(ko, DB) {
define(
[
'knockout',
'../db/db',
'../config-service/config-service',
'../template-service/template-service'
], function(ko, DB, configService, templateService) {
function GenericRoute() {
var self = this;
@ -14,6 +20,16 @@ define(['knockout', '../db/db'], function(ko, DB) {
page(parseInt(route.pageNumber, 10));
}
}
self.resolveTemplate = function(originalTemplate, templateName) {
if (templateName in configService.customTemplates
&& configService.customTemplates[templateName]) {
return templateService.loadTemplate(templateName, configService.customTemplates[templateName]);
}
else {
return originalTemplate;
}
}
}
// This runs when the component is torn down. Put here any logic necessary to clean up,

View file

@ -1,4 +1,10 @@
define(['knockout', 'text!./home.html', '../generic-route/generic-route', '../db/db'],
define(
[
'knockout',
'text!./home.html',
'../generic-route/generic-route',
'../db/db'
],
function(ko, templateMarkup, GR, DB) {
function HomePage(route) {
@ -15,6 +21,8 @@ define(['knockout', 'text!./home.html', '../generic-route/generic-route', '../db
// for example cancelling setTimeouts or disposing Knockout subscriptions/computeds.
HomePage.prototype.dispose = function() {};
templateMarkup = GR.resolveTemplate(templateMarkup, 'home');
return { viewModel: HomePage, template: templateMarkup };
});

View file

@ -0,0 +1,32 @@
define(['knockout'], function(ko) {
function TemplateService() {
var self = this;
self.templateStore = {};
self.loadTemplate = function(templateName, templateUrl) {
if (templateName in self.templateStore) {
return self.templateStore[templateName];
}
else {
var html = $.ajax(templateUrl, {
// We need to set async false to receive the template before rendering
// starts
async: false,
dataType: 'html'
}).responseText;
self.templateStore[templateName] = html;
return html;
}
};
}
// This runs when the component is torn down. Put here any logic necessary to clean up,
// for example cancelling setTimeouts or disposing Knockout subscriptions/computeds.
TemplateService.prototype.dispose = function() { };
return new TemplateService();
});

View file

@ -18,5 +18,30 @@ LAINE_CONFIG = {
pageCommenting: false,
// Posts shown per page
postsPerPage: 5
postsPerPage: 5,
// GOOGLE ANALYTICS
useGa: false, // Set to true to use Google Analytics
webPropertyID: '', // Your Google Analytics UA-XXXX-Y code
// CUSTOM TEMPLATE AND CSS OVERRIDES
// To load a custom CSS file, insert the file name below
customCss: '',
// To replace builtin templates with custom teplates, insert the file names
// below in the correct places. The paths should be relative to the
// index.html path.
customTemplates: {
navbar: '', // Navigation bar
home: '', // Home page
post: '', // Single post/page
pagination: '', // A list of posts with included pagination
year: '', // Year archives
month: '', // Month archives
tag: '' // Tag archives
}
};